From 1421131a0ae2d44a5eb6ef976a7b26af00322c81 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:30:19 -0700 Subject: [PATCH 01/97] feat: cross-panel Favorites view with sub-device support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a synthetic "Favorites" entry to the dashboard panel dropdown that aggregates favorited circuits and sub-devices (BESS, EVSE) from every configured SPAN panel into a single workspace. - Heart toggles in the Graph Settings side panel and per-circuit / per-sub-device side panels (dashboard mode only — never in standalone card). Per-row hearts in panel-mode for both circuits and sub-devices. - Favorites view shows By Activity / By Area / Monitoring tabs (no By Panel) with circuit names prefixed by panel name when more than one panel contributes. Sub-devices render as tiles above the circuit list. Monitoring stacks per-panel blocks. - Persistent panel-stats header lifted out of the By-Panel grid so it stays visible across all tabs (real panels). Favorites pseudo-panel shows a summary strip + W/A unit toggle instead. - Stateful Favorites view: active tab, expanded composite ids, and search query persist via localStorage and restore exactly on return. - Side-panel domain service calls thread an optional config_entry_id so cross-panel favorites edits target the originating panel. DashboardController bypasses single-entry caches in favorites view and fetches per-entry settings on demand. - Heart UI uses the entity_id-based service API — UUIDs and sub-device device_ids are an internal storage concern. - Skip rendering ha-menu-button until hass is set; it reads this.hass.kioskMode in willUpdate. Bumps version to 0.9.3. --- dist/span-panel-card.js | 24 +- dist/span-panel.js | 40 +-- package.json | 2 +- src/card/span-panel-card.ts | 6 +- src/constants.ts | 2 +- src/core/dashboard-controller.ts | 175 +++++++++++- src/core/favorites-controller.ts | 136 +++++++++ src/core/favorites-store.ts | 142 ++++++++++ src/core/header-renderer.ts | 20 +- src/core/list-view-controller.ts | 84 +++++- src/core/side-panel.ts | 336 ++++++++++++++++++++-- src/i18n.ts | 32 +++ src/panel/span-panel.ts | 470 ++++++++++++++++++++++++++++--- src/panel/tab-dashboard.ts | 15 + src/panel/tab-monitoring.ts | 6 +- src/types.ts | 42 +++ 16 files changed, 1415 insertions(+), 117 deletions(-) create mode 100644 src/core/favorites-controller.ts create mode 100644 src/core/favorites-store.ts diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js index 9d806e7..1532a14 100644 --- a/dist/span-panel-card.js +++ b/dist/span-panel-card.js @@ -1,42 +1,42 @@ -let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){e=n&&t[n]?n:"en"}function i(n){return t[e]?.[n]??t.en?.[n]??n}const s="power",o="5m",a={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},r="span_panel",c="CLOSED",l="pv",d="bess",h="evse",p="sub_",u=500,g={power:{entityRole:"power",label:()=>i("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>i("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},_={soc:{entityRole:"soc",label:()=>i("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>i("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:g.power},f={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>i("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>i("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>i("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>i("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>i("shedding.unknown")}},m="#ff9800";function v(e,t,n,i){var s,o=arguments.length,a=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,i);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,n,a):s(t,n))||a);return o>3&&a&&Object.defineProperty(t,n,a),a}"function"==typeof SuppressedError&&SuppressedError; +let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 circuit across {panels} panels","panel.favorites_summary_many":"{circuits} circuits across {panels} panels","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito en {panels} paneles","panel.favorites_summary_many":"{circuits} circuitos en {panels} paneles","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 circuit sur {panels} panneaux","panel.favorites_summary_many":"{circuits} circuits sur {panels} panneaux","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"{panels} パネルにわたる 1 回路","panel.favorites_summary_many":"{panels} パネルにわたる {circuits} 回路","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito em {panels} painéis","panel.favorites_summary_many":"{circuits} circuitos em {panels} painéis","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function i(i){e=i&&t[i]?i:"en"}function n(i){return t[e]?.[i]??t.en?.[i]??i}const s="power",o="5m",a={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},r="span_panel",c="CLOSED",l="pv",d="bess",h="evse",p="sub_",u=500,g={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},_={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:g.power},f={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},m="#ff9800";function v(e,t,i,n){var s,o=arguments.length,a=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,n);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,i,a):s(t,i))||a);return o>3&&a&&Object.defineProperty(t,i,a),a}"function"==typeof SuppressedError&&SuppressedError; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const b=globalThis,y=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,w=Symbol(),x=new WeakMap;let S=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==w)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(y&&void 0===e){const n=void 0!==t&&1===t.length;n&&(e=x.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&x.set(t,e))}return e}toString(){return this.cssText}};const C=e=>new S("string"==typeof e?e:e+"",void 0,w),$=y?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const n of e.cssRules)t+=n.cssText;return C(t)})(e):e,{is:E,defineProperty:z,getOwnPropertyDescriptor:k,getOwnPropertyNames:A,getOwnPropertySymbols:M,getPrototypeOf:P}=Object,L=globalThis,N=L.trustedTypes,T=N?N.emptyScript:"",D=L.reactiveElementPolyfillSupport,H=(e,t)=>e,O={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=null!==e;break;case Number:n=null===e?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch(e){n=null}}return n}},R=(e,t)=>!E(e,t),I={attribute:!0,type:String,converter:O,reflect:!1,useDefault:!1,hasChanged:R}; +const b=globalThis,y=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,w=Symbol(),x=new WeakMap;let S=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==w)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(y&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=x.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&x.set(t,e))}return e}toString(){return this.cssText}};const C=e=>new S("string"==typeof e?e:e+"",void 0,w),E=y?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return C(t)})(e):e,{is:$,defineProperty:z,getOwnPropertyDescriptor:k,getOwnPropertyNames:A,getOwnPropertySymbols:P,getPrototypeOf:M}=Object,L=globalThis,N=L.trustedTypes,D=N?N.emptyScript:"",T=L.reactiveElementPolyfillSupport,I=(e,t)=>e,H={toAttribute(e,t){switch(t){case Boolean:e=e?D:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},F=(e,t)=>!$(e,t),R={attribute:!0,type:String,converter:H,reflect:!1,useDefault:!1,hasChanged:F}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;let j=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=I){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(e,n,t);void 0!==i&&z(this.prototype,e,i)}}static getPropertyDescriptor(e,t,n){const{get:i,set:s}=k(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:i,set(t){const o=i?.call(this);s?.call(this,t),this.requestUpdate(e,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??I}static _$Ei(){if(this.hasOwnProperty(H("elementProperties")))return;const e=P(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(H("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(H("properties"))){const e=this.properties,t=[...A(e),...M(e)];for(const n of t)this.createProperty(n,e[n])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const n=this._$Eu(e,t);void 0!==n&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const n=new Set(e.flat(1/0).reverse());for(const e of n)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const n=t.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(y)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const n of t){const t=document.createElement("style"),i=b.litNonce;void 0!==i&&t.setAttribute("nonce",i),t.textContent=n.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){const n=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,n);if(void 0!==i&&!0===n.reflect){const s=(void 0!==n.converter?.toAttribute?n.converter:O).toAttribute(t,n.type);this._$Em=e,null==s?this.removeAttribute(i):this.setAttribute(i,s),this._$Em=null}}_$AK(e,t){const n=this.constructor,i=n._$Eh.get(e);if(void 0!==i&&this._$Em!==i){const e=n.getPropertyOptions(i),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:O;this._$Em=i;const o=s.fromAttribute(t,e.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(e,t,n,i=!1,s){if(void 0!==e){const o=this.constructor;if(!1===i&&(s=this[e]),n??=o.getPropertyOptions(e),!((n.hasChanged??R)(s,t)||n.useDefault&&n.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:i,wrapped:s},o){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===i&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,n]of e){const{wrapped:e}=n,i=this[t];!0!==e||this._$AL.has(t)||void 0===i||this.C(t,void 0,n,i)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};j.elementStyles=[],j.shadowRootOptions={mode:"open"},j[H("elementProperties")]=new Map,j[H("finalized")]=new Map,D?.({ReactiveElement:j}),(L.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;let O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=R){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&z(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=k(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??R}static _$Ei(){if(this.hasOwnProperty(I("elementProperties")))return;const e=M(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(I("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(I("properties"))){const e=this.properties,t=[...A(e),...P(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(E(e))}else void 0!==e&&t.push(E(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(y)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=b.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:H).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:H;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??F)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[I("elementProperties")]=new Map,O[I("finalized")]=new Map,T?.({ReactiveElement:O}),(L.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const q=globalThis,F=e=>e,W=q.trustedTypes,U=W?W.createPolicy("lit-html",{createHTML:e=>e}):void 0,B="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,Q=`<${V}>`,J=document,X=()=>J.createComment(""),K=e=>null===e||"object"!=typeof e&&"function"!=typeof e,Z=Array.isArray,Y="[ \t\n\f\r]",ee=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,te=/-->/g,ne=/>/g,ie=RegExp(`>|${Y}(?:([^\\s"'>=/]+)(${Y}*=${Y}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),se=/'/g,oe=/"/g,ae=/^(?:script|style|textarea|title)$/i,re=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ce=Symbol.for("lit-noChange"),le=Symbol.for("lit-nothing"),de=new WeakMap,he=J.createTreeWalker(J,129);function pe(e,t){if(!Z(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==U?U.createHTML(t):t}const ue=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"",a=ee;for(let t=0;t"===c[0]?(a=s??ee,l=-1):void 0===c[1]?l=-2:(l=a.lastIndex-c[2].length,r=c[1],a=void 0===c[3]?ie:'"'===c[3]?oe:se):a===oe||a===se?a=ie:a===te||a===ne?a=ee:(a=ie,s=void 0);const h=a===ie&&e[t+1].startsWith("/>")?" ":"";o+=a===ee?n+Q:l>=0?(i.push(r),n.slice(0,l)+B+n.slice(l)+G+h):n+G+(-2===l?t:h)}return[pe(e,o+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class ge{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[c,l]=ue(e,t);if(this.el=ge.createElement(c,n),he.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=he.nextNode())&&r.length0){i.textContent=W?W.emptyScript:"";for(let n=0;nZ(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==le&&K(this._$AH)?this._$AA.nextSibling.data=e:this.T(J.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=ge.createElement(pe(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new fe(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=de.get(e.strings);return void 0===t&&de.set(e.strings,t=new ge(e)),t}k(e){Z(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new me(this.O(X()),this.O(X()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=le}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=_e(this,e,t,0),o=!K(e)||e!==this._$AH&&e!==ce,o&&(this._$AH=e);else{const i=e;let a,r;for(e=s[0],a=0;ae,U=j.trustedTypes,W=U?U.createPolicy("lit-html",{createHTML:e=>e}):void 0,G="$lit$",B=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+B,Q=`<${V}>`,J=document,X=()=>J.createComment(""),K=e=>null===e||"object"!=typeof e&&"function"!=typeof e,Z=Array.isArray,Y="[ \t\n\f\r]",ee=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,te=/-->/g,ie=/>/g,ne=RegExp(`>|${Y}(?:([^\\s"'>=/]+)(${Y}*=${Y}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),se=/'/g,oe=/"/g,ae=/^(?:script|style|textarea|title)$/i,re=(e=>(t,...i)=>({_$litType$:e,strings:t,values:i}))(1),ce=Symbol.for("lit-noChange"),le=Symbol.for("lit-nothing"),de=new WeakMap,he=J.createTreeWalker(J,129);function pe(e,t){if(!Z(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==W?W.createHTML(t):t}const ue=(e,t)=>{const i=e.length-1,n=[];let s,o=2===t?"":3===t?"":"",a=ee;for(let t=0;t"===c[0]?(a=s??ee,l=-1):void 0===c[1]?l=-2:(l=a.lastIndex-c[2].length,r=c[1],a=void 0===c[3]?ne:'"'===c[3]?oe:se):a===oe||a===se?a=ne:a===te||a===ie?a=ee:(a=ne,s=void 0);const h=a===ne&&e[t+1].startsWith("/>")?" ":"";o+=a===ee?i+Q:l>=0?(n.push(r),i.slice(0,l)+G+i.slice(l)+B+h):i+B+(-2===l?t:h)}return[pe(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class ge{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[c,l]=ue(e,t);if(this.el=ge.createElement(c,i),he.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=he.nextNode())&&r.length0){n.textContent=U?U.emptyScript:"";for(let i=0;iZ(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==le&&K(this._$AH)?this._$AA.nextSibling.data=e:this.T(J.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=ge.createElement(pe(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new fe(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=de.get(e.strings);return void 0===t&&de.set(e.strings,t=new ge(e)),t}k(e){Z(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const s of e)n===t.length?t.push(i=new me(this.O(X()),this.O(X()),this,this.options)):i=t[n],i._$AI(s),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=le}_$AI(e,t=this,i,n){const s=this.strings;let o=!1;if(void 0===s)e=_e(this,e,t,0),o=!K(e)||e!==this._$AH&&e!==ce,o&&(this._$AH=e);else{const n=e;let a,r;for(e=s[0],a=0;a{const i=n?.renderBefore??t;let s=i._$litPart$;if(void 0===s){const e=n?.renderBefore??null;i._$litPart$=s=new me(t.insertBefore(X(),e),e,void 0,n??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ce}}$e._$litElement$=!0,$e.finalized=!0,Ce.litElementHydrateSupport?.({LitElement:$e});const Ee=Ce.litElementPolyfillSupport;Ee?.({LitElement:$e}),(Ce.litElementVersions??=[]).push("4.2.2"); + */class Ee extends O{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((e,t,i)=>{const n=i?.renderBefore??t;let s=n._$litPart$;if(void 0===s){const e=i?.renderBefore??null;n._$litPart$=s=new me(t.insertBefore(X(),e),e,void 0,i??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ce}}Ee._$litElement$=!0,Ee.finalized=!0,Ce.litElementHydrateSupport?.({LitElement:Ee});const $e=Ce.litElementPolyfillSupport;$e?.({LitElement:Ee}),(Ce.litElementVersions??=[]).push("4.2.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const ze={attribute:!0,type:String,converter:O,reflect:!1,hasChanged:R},ke=(e=ze,t,n)=>{const{kind:i,metadata:s}=n;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===i&&((e=Object.create(e)).wrapped=!0),o.set(n.name,e),"accessor"===i){const{name:i}=n;return{set(n){const s=t.get.call(this);t.set.call(this,n),this.requestUpdate(i,s,e,!0,n)},init(t){return void 0!==t&&this.C(i,void 0,e,t),t}}}if("setter"===i){const{name:i}=n;return function(n){const s=this[i];t.call(this,n),this.requestUpdate(i,s,e,!0,n)}}throw Error("Unsupported decorator location: "+i)}; +const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:F},ke=(e=ze,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Ae(e){return(t,n)=>"object"==typeof n?ke(e,t,n):((e,t,n)=>{const i=t.hasOwnProperty(n);return t.constructor.createProperty(n,e),i?Object.getOwnPropertyDescriptor(t,n):void 0})(e,t,n)} + */function Ae(e){return(t,i)=>"object"==typeof i?ke(e,t,i):((e,t,i)=>{const n=t.hasOwnProperty(i);return t.constructor.createProperty(i,e),n?Object.getOwnPropertyDescriptor(t,i):void 0})(e,t,i)} /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Me(e){return Ae({...e,state:!0,attribute:!1})}const Pe={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Pe[e]??e)}const Ne=g.power;function Te(e){return Ne.unit(e)}function De(e){return(e<0?"-":"")+Ne.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Oe(e){return Math.ceil(e/2)}function Re(e){return e%2==0?1:0}function Ie(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Oe(t)===Oe(n)?"row-span":Re(t)===Re(n)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const n=function(e){return je(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class Fe{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ue(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,n,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||i("grid.unknown")),$=je(r);let E;if("current"===$.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${$.format(i)}A`}else E=`${De(_)}${Te(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),M=A?m:"#555",P=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${i(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${P}\n
\n
\n
\n `}function Ge(e,t){return`\n
\n \n
\n `}const Ve={names:["power","battery power"],suffixes:["_power"]},Qe={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Je={names:["state of energy"],suffixes:["_soe_kwh"]},Xe={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ke(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function Ze(e){return Ke(e,Ve)}function Ye(e){return Ke(e,Qe)}function et(e){return Ke(e,Je)}function tt(e){return Ke(e,Xe)}function nt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||n;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function it(e,t,n,s,o,a){if(n){const t=[{key:`${p}${e}_soc`,title:i("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:i("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:i("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function st(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function ot(e){const t=a[e];return t?t.ms:a[o].ms}function at(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function rt(e){return Math.max(500,Math.floor(e/5e3))}function ct(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function lt(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function dt(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function ht(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=at(i),c=rt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,lt(t,r,c))}}}function pt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:Ze(i)};i.type===d&&(e.soc=Ye(i),e.soe=et(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${n}_${i}`,devId:n})}return t}async function ut(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=qe(i,n);if(!t)continue;let o;o=s&&s.has(e)?ot(s.get(e)):st(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of pt(t)){let t;t=o&&o.has(s)?ot(o.get(s)):st(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(dt(e,n.entityIds,n.uuidByEntity,t,i)):r.push(ht(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function gt(e,t,n,i,o,a,r,c,l){const{options:d,series:h}=function(e,t,n,i,o,a=!1){n||(n=g[s]);const r=i?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:m,series:u}}(n,i,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function _t(e,t,n,s,o,a){if(!e||!n||!t)return;const r=st(s);let d=0;for(const[,e]of Object.entries(n.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,n,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(n.circuits)){const n=e.querySelector(`[data-uuid="${s}"]`);if(!n)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=n.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${De(_)}${Te(_)}`;const x=n.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=i(y?"grid.on":"grid.off"))}let S;if(n.classList.toggle("circuit-off",!y),n.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;S=n?n.state:"unknown"}const C=f[S]??f.unknown,$=n.querySelector(".shedding-icon");$&&($.setAttribute("icon",C.icon),$.style.color=C.color,$.title=C.label());const E=n.querySelector(".shedding-icon-secondary");E&&(C.icon2?(E.setAttribute("icon",C.icon2),E.style.color=C.color,E.style.display=""):E.style.display="none");const z=n.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=n.querySelector(".chart-container");if(k){const e=o.get(s)||[],i=n.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?ot(a.get(s)):r,p=d.device_type===l;gt(k,t,e,c,h,m,i,d.breaker_rating_a??void 0,p)}}}class ft{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function mt(e,t){if(!e)return o;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??o}function vt(e,t){if(!e)return o;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??o}class bt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Fe,this.graphSettingsCache=new ft,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,mt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,vt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await ut(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??o;if(!a[i]?.useRealtime)continue;const s=qe(n,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=ot(i),d=at(l),h=rt(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of pt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await ut(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(_t(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=st(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const c=Ze(r);if(c){const e=t.states[c],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${De(i)} ${Te(i)}`)}const l=n.querySelectorAll("[data-chart-key]");for(const e of l){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let c=_.power;n.endsWith("_soc")?c=_.soc:n.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");gt(e,t,r,o?.has(i)?ot(o.get(i)):a,c,!1,l?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,i.classList.contains("panel-gear"))return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings});const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){await this.monitoringCache.fetch(this._hass,this._configEntryId);const t=e.entities?.current??e.entities?.power,n=t?this.monitoringCache.status?.circuits?.[t]??null:null;await this.graphSettingsCache.fetch(this._hass,this._configEntryId);const i=this.graphSettingsCache.settings,r=i?.global_horizon??o,c=i?.circuits?.[a],l=c?{...c,globalHorizon:r}:{horizon:r,has_override:!1,globalHorizon:r};return void s.open({...e,uuid:a,monitoringInfo:n,showMonitoring:this._showMonitoring,graphHorizonInfo:l})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r];await this.graphSettingsCache.fetch(this._hass,this._configEntryId);const t=this.graphSettingsCache.settings,n=t?.global_horizon??o,i=t?.sub_devices?.[r],a=i?{...i,globalHorizon:n}:{horizon:n,has_override:!1,globalHorizon:n};s.open({subDeviceMode:!0,subDeviceId:r,name:e.name??r,deviceType:e.type??"",graphHorizonInfo:a})}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function yt(e=""){const t=e?` value="${Le(e)}"`:"",n=e?"":"display:none;";return`\n
\n \n \n
\n `}function wt(e){const t="current"===(e.chart_metric||"power");return`\n
\n \n \n
\n `}function xt(e,t,n,s,o,a,r){const l=t.entities?.power,d=l?n.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?n.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||i("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,i=e?n.states[e]:null,s=i&&parseFloat(i.state)||0;w=`${b.format(s)}A`}else w=`${De(h)}${Te(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const $=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${$}\n \n ${w}\n \n \n
\n `}function St(e,t,n,i,s,o){const a=Be(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function $t(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;l=i?Math.abs(parseFloat(i.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function Et(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function zt(e,t,n){return e.sort((e,i)=>{const s=$t(e[1],t,n),o=$t(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._ctrl=e}renderActivityView(e,t,n,i,s){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const o=zt(Object.entries(n.circuits),t,i);let a=yt(this._searchQuery)+wt(i);a+='
';for(const[e,n]of o){const o=We(s,kt(n)),r=Et(n,t),c=this._expandedUuids.has(e);a+=xt(e,n,t,i,o,r,c),c&&(a+=St(e,n,t,i,o,r))}a+="
",a+="",e.innerHTML=a;const r=e.querySelector("span-side-panel");r&&(r.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,n,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=s,this._monitoringStatus=o;const a=i("list.unassigned_area"),r=new Map;for(const[e,t]of Object.entries(n.circuits)){const n=t.area??a,i=r.get(n);i?i.push([e,t]):r.set(n,[[e,t]])}const c=[...r.keys()].sort((e,t)=>e===a?1:t===a?-1:e.localeCompare(t));let l=yt(this._searchQuery)+wt(s);l+='
';for(const e of c){const n=r.get(e);if(!n)continue;const i=zt(n,t,s);l+=Ct(e);for(const[e,n]of i){const i=We(o,kt(n)),a=Et(n,t),r=this._expandedUuids.has(e);l+=xt(e,n,t,s,i,a,r),r&&(l+=St(e,n,t,s,i,a))}}l+="
",l+="",e.innerHTML=l;const d=e.querySelector("span-side-panel");d&&(d.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=je(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:c,value:l}=$t(r,t,i),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${De(i)}${Te(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),this._expandedUuids.clear(),this._searchQuery="",this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e))},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t)if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=We(this._monitoringStatus,kt(i)),o=Et(i,this._hass),a=St(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}}}async function Mt(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Pt(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);class Tt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,n=this._createHeader(i("sidepanel.graph_settings"),i("sidepanel.global_defaults"));e.appendChild(n);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=i("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=i("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{this._callDomainService("set_graph_time_horizon",{horizon:m.value}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const t=document.createElement("div");t.className="section-label",t.textContent=i("sidepanel.circuit_scales"),e.appendChild(t);const n=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[t,s]of n){const n=document.createElement("div");n.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=s.name||t,o.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",n.appendChild(o);const r=h[t]||{horizon:d,has_override:!1},c=r.has_override?r.horizon:d,l=document.createElement("select");l.dataset.uuid=t;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===c&&(t.selected=!0),l.appendChild(t)}if(l.addEventListener("change",()=>{this._debounce(`circuit-${t}`,u,()=>{this._callDomainService("set_circuit_graph_horizon",{circuit_id:t,horizon:l.value}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),n.appendChild(l),r.has_override){const e=document.createElement("button");e.textContent="↺",e.title=i("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{this._callDomainService("clear_circuit_graph_horizon",{circuit_id:t}).then(()=>{l.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),n.appendChild(e)}e.appendChild(n)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const t=document.createElement("div");t.className="section-label",t.textContent=i("sidepanel.subdevice_scales"),e.appendChild(t);const n=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[t,s]of n){const n=document.createElement("div");n.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=s.name||t,o.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",n.appendChild(o);const r=v[t]||{horizon:d,has_override:!1},c=r.has_override?r.horizon:d,l=document.createElement("select");l.dataset.subdevId=t;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===c&&(t.selected=!0),l.appendChild(t)}if(l.addEventListener("change",()=>{this._debounce(`subdev-${t}`,u,()=>{this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:t,horizon:l.value}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),n.appendChild(l),r.has_override){const e=document.createElement("button");e.textContent="↺",e.title=i("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:t}).then(()=>{l.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),n.appendChild(e)}e.appendChild(n)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const n=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,i=this._createHeader(Le(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_renderSubDeviceMode(e,t){const n=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceHorizonSection(e,t){const n=document.createElement("div");n.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=i("sidepanel.graph_horizon"),n.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:i("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:n}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=n,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const n=t.subDeviceId;"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:n}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:n,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}n.appendChild(h),e.appendChild(n)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Le(e),o=Le(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const n=document.createElement("div");n.className="section",n.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=i("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${i("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),n.appendChild(s),e.appendChild(n)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const n=document.createElement("div");n.className="section",n.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=i("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of Nt){const t=f[e];if(!t)continue;const n=document.createElement("option");n.value=e,n.textContent=i(`shedding.select.${e}`)||t.label(),e===c&&(n.selected=!0),a.appendChild(n)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${i("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),n.appendChild(s),e.appendChild(n)}_renderGraphHorizonSection(e,t){const n=document.createElement("div");n.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=i("sidepanel.graph_horizon"),n.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:i("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:n}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=n,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const n=t.uuid;"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",{circuit_id:n}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{circuit_id:n,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}n.appendChild(h),e.appendChild(n)}_renderMonitoringSection(e,t){const n=document.createElement("div");n.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=i("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),n.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",n.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(i("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(i("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(i("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(i("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const n=t.entities?.power||t.uuid;this._callDomainService("set_circuit_threshold",{circuit_id:n,monitoring_enabled:e}).catch(e=>this._showError(`${i("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const n="custom"===e.value&&e.checked;if(p.style.display=n?"block":"none",!n&&e.checked){const e=t.entities?.power||t.uuid;this._callDomainService("clear_circuit_threshold",{circuit_id:e}).catch(e=>this._showError(`${i("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(n)}_createThresholdRow(e,t,n,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(n),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),n=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r=s.entities?.power||s.uuid;this._callDomainService("set_circuit_threshold",{circuit_id:r,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:n?Number(n.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0}).catch(e=>this._showError(`${i("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,n,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(n),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),n=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]');this._callDomainService("set_circuit_threshold",{circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:n?Number(n.value):void 0,window_duration_m:s?Number(s.value):void 0}).catch(e=>this._showError(`${i("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Tt)}catch{}const Dt=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let Ht=class extends $e{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new bt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return n(this.hass?.language),this._config.device_id?this._discovered?re` + */function Pe(e){return Ae({...e,state:!0,attribute:!1})}const Me={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Me[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Te(e){return De.unit(e)}function Ie(e){return(e<0?"-":"")+De.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Fe(e){return Math.ceil(e/2)}function Re(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Fe(t)===Fe(i)?"row-span":Re(t)===Re(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${Ie(_)}${Te(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?m:"#555",M=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${M}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${Ie(_)}${Te(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${Ie(n)} ${Te(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Ie(h)}${Te(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${Ie(n)}${Te(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Mt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}async function Tt(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}async function It(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}const Ht=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);function Ft(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Rt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Tt(this._hass,i):await It(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=Ft(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Tt(this._hass,t):await It(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=Ft(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i=t.subDeviceId;"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:i}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of Ht){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Rt)}catch{}const Ot=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let jt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re` `:re` -
${Le(i("card.loading"))}
+
${Le(n("card.loading"))}
- `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(n(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await Mt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(i("card.device_not_found"));const n=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=n.panel_size??Pt(n.circuits);if(!s)throw new Error(i("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Mt(e,n),{topology:n,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[n,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(n.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=n.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const n=e.states[t.entity_id];if(!n)continue;const i=n.attributes,s=i.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof i.friendly_name?i.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof i.voltage?i.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof i.device_type?i.device_type:"circuit",relay_state:"string"==typeof i.relay_state?i.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const n=e.states[t.entity_id];if(n&&"number"==typeof n.attributes.panel_size){g=n.attributes.panel_size;break}}if(g||(g=Pt(h)),!g)throw new Error(i("card.panel_size_error"));const _={};for(const t of c){const n=s.filter(e=>e.device_id===t.id),i=(t.model??"").toLowerCase(),o=i.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=i.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of n){const n=t.entity_id.split(".")[0],i=e.states[t.entity_id],s=i?.attributes?.friendly_name;r[t.entity_id]={domain:n??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??i("header.default_name"),circuits:h,sub_devices:_};return await Mt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:i("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:i("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:i("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(n=e,s=this._activeTab,o=this._config.tab_style??"text",`
${n.map(e=>{const t=e.id===s?" active":"",n=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const n=e=>{const n=e.target.closest(".shared-tab");if(n){const e=n.dataset.tab;e&&t(e)}};return e.addEventListener("click",n),()=>{e.removeEventListener("click",n)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var n,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),n=function(e,t){const n=Le(e.device_name||i("header.default_name")),s=Le(e.serial||""),o=Le(e.firmware||""),a="current"===(t.chart_metric||"power"),r=!!e.panel_entities?.site_power,c=!!e.panel_entities?.dsm_state,l=!!e.panel_entities?.current_power,d=!!e.panel_entities?.feedthrough_power,h=!!e.panel_entities?.pv_power,p=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${n}

\n ${s}\n \n
\n ${i("header.enable_switches")}\n
\n \n
\n
\n
\n
\n ${r?`\n
\n ${i("header.site")}\n
\n 0\n ${a?"A":"kW"}\n
\n
`:""}\n ${c?`\n
\n ${i("header.grid")}\n
\n --\n
\n
`:""}\n ${l?`\n
\n ${i("header.upstream")}\n
\n --\n ${a?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${i("header.downstream")}\n
\n --\n ${a?"A":"kW"}\n
\n
`:""}\n ${h?`\n
\n ${i("header.solar")}\n
\n --\n ${a?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${i("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${o}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),n=Object.values(e.mains??{}),s=[...t,...n],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${i("status.monitoring")} · ${t.length} ${i("status.circuits")} · ${n.length} ${i("status.mains")}\n \n ${o>0?`${o} ${i(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${i(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${i(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ie(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Oe(Math.max(...n));0===Re(e)?r.add(i):c.add(i)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ge(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ge(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,n){const s=!1!==n.show_battery,o=!1!==n.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?i("subdevice.ev_charger"):s.type===d?i("subdevice.battery"):i("subdevice.fallback"),a=Ze(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?Ye(s):null,m=g?et(s):null,v=g?tt(s):null,b=nt(s,t,n,new Set([a,f,m,v].filter(e=>null!==e))),y=it(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${De(u)} ${Te(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${n}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else"activity"===this._activeTab?(e.innerHTML="",this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status),this._ctrl.updateDOM(this.shadowRoot)):"area"===this._activeTab&&(e.innerHTML="",this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status),this._ctrl.updateDOM(this.shadowRoot))}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const n=t.closest(".unit-btn");if(n)return void this._onUnitToggle(n);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Dt.map(e=>re` + `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Pt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Mt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Pt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Mt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Pt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Fe(Math.max(...i));0===Re(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${Ie(u)} ${Te(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Ot.map(e=>re`
${e.name} @@ -75,7 +75,7 @@ const ze={attribute:!0,type:String,converter:O,reflect:!1,hasChanged:R},ke=(e=ze Live Power
${e}
-
${i("card.no_device")}
+
${n("card.no_device")}
- `}};Ht.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],Ht.prototype,"hass",void 0),v([Me()],Ht.prototype,"_config",void 0),v([Me()],Ht.prototype,"_discovered",void 0),v([Me()],Ht.prototype,"_discovering",void 0),v([Me()],Ht.prototype,"_discoveryError",void 0),v([Me()],Ht.prototype,"_topology",void 0),v([Me()],Ht.prototype,"_activeTab",void 0),Ht=v([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],Ht);class Ot extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",n=e.name_by_user??e.name??i("editor.panel_label");return{device_id:e.id,label:`${n} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",n="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",i="margin-bottom: 16px;";this._buildPanelSelector(e,t,n,i),this._buildTimeWindow(e,t,n,i),this._buildMetricSelector(e,t,n,i),this._buildTabStyleSelector(e,t,n,i),this._buildSectionCheckboxes(e,n,i),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,n,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=i("editor.panel_label"),a.style.cssText=n;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=i("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,n,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=i("editor.chart_window"),a.style.cssText=n;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,n,i)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=n,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=i,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",i("editor.days")),g=l(h,"0","23",i("editor.hours")),_=l(p,"0","59",i("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,n,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=i("editor.chart_metric"),a.style.cssText=n;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,n,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=i("editor.tab_style"),a.style.cssText=n;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:i("editor.tab_style_text")},{value:"icon",text:i("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,n){const s=document.createElement("div");s.style.cssText=n;const o=document.createElement("label");o.textContent=i("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:i("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:i("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:i("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const n=document.createElement("input");n.type="checkbox",n.checked=!1!==this._config[e.key],n.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const i=document.createElement("span");i.textContent=e.label,i.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(n),t.appendChild(i),s.appendChild(t),this._checkboxes[e.key]=n;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=n.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),n.addEventListener("change",()=>{this._config={...this._config,[e.key]:n.checked},o&&(o.style.display=n.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,n){const i=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===i||"battery power"===i||s.endsWith("_power"))return!0;if("bess"===n){if("battery level"===i||"battery percentage"===i||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===i||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===i||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,n]of Object.entries(e)){const e=n.type?this._entityContainers[n.type]:void 0;if(e&&(e.innerHTML="",n.entities))for(const[i,s]of Object.entries(n.entities)){if("sensor"===s.domain&&this._isChartEntity(i,s,n.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[i],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??i;const l=n.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[i]=!0:delete e[i],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),n=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))n.add(t);this._availableRoles=n,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[n,i]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(i.entityRole))continue;const s=document.createElement("option");s.value=n,s.textContent=i.label(),n===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",Ot)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.2 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); + `}};jt.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],jt.prototype,"hass",void 0),v([Pe()],jt.prototype,"_config",void 0),v([Pe()],jt.prototype,"_discovered",void 0),v([Pe()],jt.prototype,"_discovering",void 0),v([Pe()],jt.prototype,"_discoveryError",void 0),v([Pe()],jt.prototype,"_topology",void 0),v([Pe()],jt.prototype,"_activeTab",void 0),jt=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],jt);class qt extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",qt)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); diff --git a/dist/span-panel.js b/dist/span-panel.js index 2717bb6..e636985 100644 --- a/dist/span-panel.js +++ b/dist/span-panel.js @@ -1,32 +1,32 @@ -let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){return t[e]?.[n]??t.en?.[n]??n}const i="power",o="5m",s={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},a="span_panel",r="CLOSED",l="pv",c="bess",d="evse",h="sub_",p=500,u={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},g={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:u.power},_={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},f="#ff9800";function m(e,t,n,i){var o,s=arguments.length,a=s<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,i);else for(var r=e.length-1;r>=0;r--)(o=e[r])&&(a=(s<3?o(a):s>3?o(t,n,a):o(t,n))||a);return s>3&&a&&Object.defineProperty(t,n,a),a}"function"==typeof SuppressedError&&SuppressedError; +let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 circuit across {panels} panels","panel.favorites_summary_many":"{circuits} circuits across {panels} panels","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito en {panels} paneles","panel.favorites_summary_many":"{circuits} circuitos en {panels} paneles","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 circuit sur {panels} panneaux","panel.favorites_summary_many":"{circuits} circuits sur {panels} panneaux","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"{panels} パネルにわたる 1 回路","panel.favorites_summary_many":"{panels} パネルにわたる {circuits} 回路","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito em {panels} painéis","panel.favorites_summary_many":"{circuits} circuitos em {panels} painéis","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){return t[e]?.[n]??t.en?.[n]??n}const i="power",s="5m",o={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},a="span_panel",r="CLOSED",l="pv",c="bess",d="evse",h="sub_",p=500,u={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},g={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:u.power},_={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},f="#ff9800";function v(e,t,n,i){var s,o=arguments.length,a=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,i);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,n,a):s(t,n))||a);return o>3&&a&&Object.defineProperty(t,n,a),a}"function"==typeof SuppressedError&&SuppressedError; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const b=globalThis,v=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,y=Symbol(),w=new WeakMap;let x=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==y)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(v&&void 0===e){const n=void 0!==t&&1===t.length;n&&(e=w.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&w.set(t,e))}return e}toString(){return this.cssText}};const $=v?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const n of e.cssRules)t+=n.cssText;return(e=>new x("string"==typeof e?e:e+"",void 0,y))(t)})(e):e,{is:S,defineProperty:C,getOwnPropertyDescriptor:E,getOwnPropertyNames:k,getOwnPropertySymbols:z,getPrototypeOf:A}=Object,P=globalThis,M=P.trustedTypes,T=M?M.emptyScript:"",N=P.reactiveElementPolyfillSupport,D=(e,t)=>e,L={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=null!==e;break;case Number:n=null===e?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch(e){n=null}}return n}},H=(e,t)=>!S(e,t),I={attribute:!0,type:String,converter:L,reflect:!1,useDefault:!1,hasChanged:H}; +const m=globalThis,b=m.ShadowRoot&&(void 0===m.ShadyCSS||m.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,y=Symbol(),w=new WeakMap;let x=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==y)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(b&&void 0===e){const n=void 0!==t&&1===t.length;n&&(e=w.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&w.set(t,e))}return e}toString(){return this.cssText}};const $=b?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const n of e.cssRules)t+=n.cssText;return(e=>new x("string"==typeof e?e:e+"",void 0,y))(t)})(e):e,{is:S,defineProperty:C,getOwnPropertyDescriptor:E,getOwnPropertyNames:k,getOwnPropertySymbols:z,getPrototypeOf:A}=Object,P=globalThis,M=P.trustedTypes,T=M?M.emptyScript:"",I=P.reactiveElementPolyfillSupport,N=(e,t)=>e,D={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=null!==e;break;case Number:n=null===e?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch(e){n=null}}return n}},L=(e,t)=>!S(e,t),F={attribute:!0,type:String,converter:D,reflect:!1,useDefault:!1,hasChanged:L}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),P.litPropertyMetadata??=new WeakMap;let O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=I){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(e,n,t);void 0!==i&&C(this.prototype,e,i)}}static getPropertyDescriptor(e,t,n){const{get:i,set:o}=E(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:i,set(t){const s=i?.call(this);o?.call(this,t),this.requestUpdate(e,s,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??I}static _$Ei(){if(this.hasOwnProperty(D("elementProperties")))return;const e=A(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(D("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(D("properties"))){const e=this.properties,t=[...k(e),...z(e)];for(const n of t)this.createProperty(n,e[n])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const n=this._$Eu(e,t);void 0!==n&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const n=new Set(e.flat(1/0).reverse());for(const e of n)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const n=t.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(v)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const n of t){const t=document.createElement("style"),i=b.litNonce;void 0!==i&&t.setAttribute("nonce",i),t.textContent=n.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){const n=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,n);if(void 0!==i&&!0===n.reflect){const o=(void 0!==n.converter?.toAttribute?n.converter:L).toAttribute(t,n.type);this._$Em=e,null==o?this.removeAttribute(i):this.setAttribute(i,o),this._$Em=null}}_$AK(e,t){const n=this.constructor,i=n._$Eh.get(e);if(void 0!==i&&this._$Em!==i){const e=n.getPropertyOptions(i),o="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:L;this._$Em=i;const s=o.fromAttribute(t,e.type);this[i]=s??this._$Ej?.get(i)??s,this._$Em=null}}requestUpdate(e,t,n,i=!1,o){if(void 0!==e){const s=this.constructor;if(!1===i&&(o=this[e]),n??=s.getPropertyOptions(e),!((n.hasChanged??H)(o,t)||n.useDefault&&n.reflect&&o===this._$Ej?.get(e)&&!this.hasAttribute(s._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:i,wrapped:o},s){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,s??t??this[e]),!0!==o||void 0!==s)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===i&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,n]of e){const{wrapped:e}=n,i=this[t];!0!==e||this._$AL.has(t)||void 0===i||this.C(t,void 0,n,i)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[D("elementProperties")]=new Map,O[D("finalized")]=new Map,N?.({ReactiveElement:O}),(P.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),P.litPropertyMetadata??=new WeakMap;let H=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=F){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(e,n,t);void 0!==i&&C(this.prototype,e,i)}}static getPropertyDescriptor(e,t,n){const{get:i,set:s}=E(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:i,set(t){const o=i?.call(this);s?.call(this,t),this.requestUpdate(e,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??F}static _$Ei(){if(this.hasOwnProperty(N("elementProperties")))return;const e=A(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(N("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(N("properties"))){const e=this.properties,t=[...k(e),...z(e)];for(const n of t)this.createProperty(n,e[n])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const n=this._$Eu(e,t);void 0!==n&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const n=new Set(e.flat(1/0).reverse());for(const e of n)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const n=t.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(b)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const n of t){const t=document.createElement("style"),i=m.litNonce;void 0!==i&&t.setAttribute("nonce",i),t.textContent=n.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){const n=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,n);if(void 0!==i&&!0===n.reflect){const s=(void 0!==n.converter?.toAttribute?n.converter:D).toAttribute(t,n.type);this._$Em=e,null==s?this.removeAttribute(i):this.setAttribute(i,s),this._$Em=null}}_$AK(e,t){const n=this.constructor,i=n._$Eh.get(e);if(void 0!==i&&this._$Em!==i){const e=n.getPropertyOptions(i),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:D;this._$Em=i;const o=s.fromAttribute(t,e.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(e,t,n,i=!1,s){if(void 0!==e){const o=this.constructor;if(!1===i&&(s=this[e]),n??=o.getPropertyOptions(e),!((n.hasChanged??L)(s,t)||n.useDefault&&n.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:i,wrapped:s},o){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===i&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,n]of e){const{wrapped:e}=n,i=this[t];!0!==e||this._$AL.has(t)||void 0===i||this.C(t,void 0,n,i)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};H.elementStyles=[],H.shadowRootOptions={mode:"open"},H[N("elementProperties")]=new Map,H[N("finalized")]=new Map,I?.({ReactiveElement:H}),(P.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const R=globalThis,q=e=>e,j=R.trustedTypes,U=j?j.createPolicy("lit-html",{createHTML:e=>e}):void 0,G="$lit$",F=`lit$${Math.random().toFixed(9).slice(2)}$`,W="?"+F,B=`<${W}>`,V=document,Q=()=>V.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ne=/'/g,ie=/"/g,oe=/^(?:script|style|textarea|title)$/i,se=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=V.createTreeWalker(V,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==U?U.createHTML(t):t}const he=(e,t)=>{const n=e.length-1,i=[];let o,s=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=o??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ie:ne):a===ie||a===ne?a=te:a===Y||a===ee?a=Z:(a=te,o=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";s+=a===Z?n+B:c>=0?(i.push(r),n.slice(0,c)+G+n.slice(c)+F+h):n+F+(-2===c?t:h)}return[de(e,s+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class pe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let o=0,s=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,n),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=ce.nextNode())&&r.length0){i.textContent=j?j.emptyScript:"";for(let n=0;nX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(V.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=pe.createElement(de(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ge(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const o of e)i===t.length?t.push(n=new _e(this.O(Q()),this.O(Q()),this,this.options)):n=t[i],n._$AI(o),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=re}_$AI(e,t=this,n,i){const o=this.strings;let s=!1;if(void 0===o)e=ue(this,e,t,0),s=!J(e)||e!==this._$AH&&e!==ae,s&&(this._$AH=e);else{const i=e;let a,r;for(e=o[0],a=0;ae,q=O.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ne=/'/g,ie=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ie:ne):a===ie||a===ne?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?n+W:c>=0?(i.push(r),n.slice(0,c)+U+n.slice(c)+G+h):n+G+(-2===c?t:h)}return[de(e,o+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class pe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,n),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=ce.nextNode())&&r.length0){i.textContent=q?q.emptyScript:"";for(let n=0;nX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=pe.createElement(de(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ge(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new _e(this.O(Q()),this.O(Q()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=re}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const i=e;let a,r;for(e=s[0],a=0;a{const i=n?.renderBefore??t;let o=i._$litPart$;if(void 0===o){const e=n?.renderBefore??null;i._$litPart$=o=new _e(t.insertBefore(Q(),e),e,void 0,n??{})}return o._$AI(e),o})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ae}};$e._$litElement$=!0,$e.finalized=!0,xe.litElementHydrateSupport?.({LitElement:$e});const Se=xe.litElementPolyfillSupport;Se?.({LitElement:$e}),(xe.litElementVersions??=[]).push("4.2.2"); + */let $e=class extends H{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((e,t,n)=>{const i=n?.renderBefore??t;let s=i._$litPart$;if(void 0===s){const e=n?.renderBefore??null;i._$litPart$=s=new _e(t.insertBefore(Q(),e),e,void 0,n??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ae}};$e._$litElement$=!0,$e.finalized=!0,xe.litElementHydrateSupport?.({LitElement:$e});const Se=xe.litElementPolyfillSupport;Se?.({LitElement:$e}),(xe.litElementVersions??=[]).push("4.2.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const Ce={attribute:!0,type:String,converter:L,reflect:!1,hasChanged:H},Ee=(e=Ce,t,n)=>{const{kind:i,metadata:o}=n;let s=globalThis.litPropertyMetadata.get(o);if(void 0===s&&globalThis.litPropertyMetadata.set(o,s=new Map),"setter"===i&&((e=Object.create(e)).wrapped=!0),s.set(n.name,e),"accessor"===i){const{name:i}=n;return{set(n){const o=t.get.call(this);t.set.call(this,n),this.requestUpdate(i,o,e,!0,n)},init(t){return void 0!==t&&this.C(i,void 0,e,t),t}}}if("setter"===i){const{name:i}=n;return function(n){const o=this[i];t.call(this,n),this.requestUpdate(i,o,e,!0,n)}}throw Error("Unsupported decorator location: "+i)}; +const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce,t,n)=>{const{kind:i,metadata:s}=n;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===i&&((e=Object.create(e)).wrapped=!0),o.set(n.name,e),"accessor"===i){const{name:i}=n;return{set(n){const s=t.get.call(this);t.set.call(this,n),this.requestUpdate(i,s,e,!0,n)},init(t){return void 0!==t&&this.C(i,void 0,e,t),t}}}if("setter"===i){const{name:i}=n;return function(n){const s=this[i];t.call(this,n),this.requestUpdate(i,s,e,!0,n)}}throw Error("Unsupported decorator location: "+i)}; /** * @license * Copyright 2017 Google LLC @@ -46,22 +46,20 @@ const Ce={attribute:!0,type:String,converter:L,reflect:!1,hasChanged:H},Ee=(e=Ce * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ne={"&":"&","<":"<",">":">",'"':""","'":"'"};function De(e){return String(e).replace(/[&<>"']/g,e=>Ne[e]??e)}const Le=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);class He extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const o=document.createElement("div");o.className="panel",t.appendChild(o),e.panelMode?this._renderPanelMode(o):e.subDeviceMode?this._renderSubDeviceMode(o,e):this._renderCircuitMode(o,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??o,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(s)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,o=n(i);t.textContent=o!==i?o:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{this._callDomainService("set_graph_time_horizon",{horizon:m.value}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const t=document.createElement("div");t.className="section-label",t.textContent=n("sidepanel.circuit_scales"),e.appendChild(t);const i=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[t,o]of i){const i=document.createElement("div");i.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=o.name||t,a.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",i.appendChild(a);const r=h[t]||{horizon:d,has_override:!1},l=r.has_override?r.horizon:d,c=document.createElement("select");c.dataset.uuid=t;for(const e of Object.keys(s)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,o=n(i);t.textContent=o!==i?o:e,e===l&&(t.selected=!0),c.appendChild(t)}if(c.addEventListener("change",()=>{this._debounce(`circuit-${t}`,p,()=>{this._callDomainService("set_circuit_graph_horizon",{circuit_id:t,horizon:c.value}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),i.appendChild(c),r.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{this._callDomainService("clear_circuit_graph_horizon",{circuit_id:t}).then(()=>{c.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),i.appendChild(e)}e.appendChild(i)}a.appendChild(e)}const b=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const t=document.createElement("div");t.className="section-label",t.textContent=n("sidepanel.subdevice_scales"),e.appendChild(t);const i=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[t,o]of i){const i=document.createElement("div");i.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=o.name||t,a.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",i.appendChild(a);const r=b[t]||{horizon:d,has_override:!1},l=r.has_override?r.horizon:d,c=document.createElement("select");c.dataset.subdevId=t;for(const e of Object.keys(s)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,o=n(i);t.textContent=o!==i?o:e,e===l&&(t.selected=!0),c.appendChild(t)}if(c.addEventListener("change",()=>{this._debounce(`subdev-${t}`,p,()=>{this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:t,horizon:c.value}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),i.appendChild(c),r.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:t}).then(()=>{c.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),i.appendChild(e)}e.appendChild(i)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${De(String(t.breaker_rating_a))}A · ${De(String(t.voltage))}V · Tabs [${De(String(t.tabs))}]`,i=this._createHeader(De(t.name),n);e.appendChild(i);const o=document.createElement("div");o.className="panel-body",e.appendChild(o);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",o.appendChild(s),this._renderRelaySection(o,t),this._renderSheddingSection(o,t),this._renderGraphHorizonSection(o,t),t.showMonitoring&&this._renderMonitoringSection(o,t)}_renderSubDeviceMode(e,t){const n=this._createHeader(De(t.name),De(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",i.appendChild(o),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(s))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const o=document.createElement("button");o.type="button",o.className="horizon-segment",o.dataset.horizon=e,o.textContent=i,o.classList.toggle("active",e===u),o.classList.toggle("referenced","global"===u&&e===d),o.addEventListener("click",()=>{if(o.classList.contains("active"))return;const i=t.subDeviceId;"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:i}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(o)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),o=De(e),s=De(t);i.innerHTML=`
${o}
`+(s?`
${s}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const o=document.createElement("div");o.className="field-row";const s=document.createElement("span");s.className="field-label",s.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),o.appendChild(s),o.appendChild(a),i.appendChild(o),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const o=document.createElement("div");o.className="field-row";const s=document.createElement("span");s.className="field-label",s.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of Le){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),o.appendChild(s),o.appendChild(a),i.appendChild(o),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(s))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const o=document.createElement("button");o.type="button",o.className="horizon-segment",o.dataset.horizon=e,o.textContent=i,o.classList.toggle("active",e===u),o.classList.toggle("referenced","global"===u&&e===d),o.addEventListener("click",()=>{if(o.classList.contains("active"))return;const i=t.uuid;"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",{circuit_id:i}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{circuit_id:i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(o)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const o=document.createElement("div");o.className="monitoring-header";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.monitoring"),s.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),o.appendChild(s),o.appendChild(a),i.appendChild(o);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i=t.entities?.power||t.uuid;this._callDomainService("set_circuit_threshold",{circuit_id:i,monitoring_enabled:e}).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e=t.entities?.power||t.uuid;this._callDomainService("clear_circuit_threshold",{circuit_id:e}).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,o){const s=document.createElement("div");s.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r=o.entities?.power||o.uuid;this._callDomainService("set_circuit_threshold",{circuit_id:r,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0,cooldown_duration_m:a?Number(a.value):void 0}).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),s.appendChild(a),s.appendChild(r),s}_createDurationRow(e,t,i,o,s,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(o),u.max=String(s),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]');this._callDomainService("set_circuit_threshold",{circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0}).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",He)}catch{}async function Ie(e,t){const[n,i,o]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),s=new Map;for(const e of n)s.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of o)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=s.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=s.get(e);break}}t||(t=l),e.area=t}}async function Oe(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),o=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!o)throw new Error(n("card.topology_error"));const s=await e.callWS({type:"config/device_registry/list"}),r=(l=s.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ie(e,i),{topology:i,panelDevice:r,panelSize:o}}const Re=u.power;function qe(e){return Re.unit(e)}function je(e){return(e<0?"-":"")+Re.format(e)}function Ue(e){return(Math.abs(e)/1e3).toFixed(1)}function Ge(e){return Math.ceil(e/2)}function Fe(e){return e%2==0?1:0}function We(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ge(t)===Ge(n)?"row-span":Fe(t)===Fe(n)?"col-span":"row-span"}function Be(e){const t=e.chart_metric??i;return u[t]??u[i]}function Ve(e,t){const n=function(e){return Be(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class Qe{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const o=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=o?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function Je(e,t){return e?.circuits?e.circuits[t]??null:null}function Xe(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Ke(e,t,i,o,s,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,m=g&&parseFloat(g.state)||0,b=t.device_type===l||m<0,v=t.entities?.switch,y=v?a.states[v]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=De(t.name||n("grid.unknown")),C=Be(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${je(m)}${qe(m)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function Ze(e,t){return`\n
\n \n
\n `}const Ye={names:["power","battery power"],suffixes:["_power"]},et={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},tt={names:["state of energy"],suffixes:["_soe_kwh"]},nt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function it(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function ot(e){return it(e,Ye)}function st(e){return it(e,et)}function at(e){return it(e,tt)}function rt(e){return it(e,nt)}function lt(e,t,n,i){const o=n.visible_sub_entities||{};let s="";if(!e.entities)return s;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==o[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}s+=`\n
\n ${De(l)}:\n ${De(d)}\n
\n `}return s}function ct(e,t,i,o,s,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!s},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!o}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${De(e.title)}
\n
\n
\n `).join("")}\n
\n `}return o?`
`:""}function dt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function ht(e){const t=s[e];return t?t.ms:s[o].ms}function pt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ut(e){return Math.max(500,Math.floor(e/5e3))}function gt(e,t,n,i,o,s){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=o);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>s&&a.splice(0,a.length-s)}function _t(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function ft(e,t,n,i,o){const s=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:s,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const s=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&s.push({time:n,value:t})}if(s.length>0){const e=o.get(i)||[],t=[...s,...e];t.sort((e,t)=>e.time-t.time),o.set(i,t)}}}async function mt(e,t,n,i,o){const s=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:s,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=pt(i),l=ut(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const s=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&s.push({time:n,value:t})}if(s.length>0){const e=o.get(i)||[],t=[...s,...e];o.set(i,_t(t,r,l))}}}function bt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:ot(i)};i.type===c&&(e.soc=st(i),e.soe=at(i));for(const[i,o]of Object.entries(e))o&&t.push({entityId:o,key:`${h}${n}_${i}`,devId:n})}return t}async function vt(e,t,n,i,o,s){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=Ve(i,n);if(!t)continue;let s;s=o&&o.has(e)?ht(o.get(e)):dt(n),a.has(s)||a.set(s,{entityIds:[],uuidByEntity:new Map});const r=a.get(s);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:o}of bt(t)){let t;t=s&&s.has(o)?ht(s.get(o)):dt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(ft(e,n.entityIds,n.uuidByEntity,t,i)):r.push(mt(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function yt(e,t,n,o,s,a,r,l,c){const{options:d,series:h}=function(e,t,n,o,s,a=!1){n||(n=u[i]);const r=o?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),s&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*s),g.push({type:"line",data:[[d,.8*s],[c,.8*s]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,s],[c,s]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),o=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(o)} ${n.unit(o)}
`}},animation:!1};return{options:m,series:g}}(n,o,s,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function wt(e,t,i,o,s,a){if(!e||!i||!t)return;const c=dt(o);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],o=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(o))}!function(e,t,n,i,o){const s="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(s){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,o=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(o)?Math.abs(o).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(o=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Ue(o)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(s){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Ue(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(s){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Ue(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(s){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Ue(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,o,d);const h=Be(o),p="current"===h.entityRole;for(const[o,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${o}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,m=d.device_type===l||f<0,b=d.entities?.switch,v=b?t.states[b]:null,y=v?"on"===v.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${je(f)}${qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=s.get(o)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(o)?ht(a.get(o)):c,p=d.device_type===l;yt(z,t,e,r,h,m,n,d.breaker_rating_a??void 0,p)}}}class xt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const o=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=o?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function $t(e,t){if(!e)return o;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??o}function St(e,t){if(!e)return o;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??o}class Ct{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Qe,this.graphSettingsCache=new xt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,$t(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,St(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await vt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??o;if(!s[i]?.useRealtime)continue;const a=Ve(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=ht(i),d=pt(c),h=ut(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of bt(this._topology))n.has(t)&&i.add(e);const o=new Map;try{await vt(this._hass,this._topology,this._config,o,t,n);for(const e of t.keys()){const t=o.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=o.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(wt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,o,s){if(!n.sub_devices)return;const a=dt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=ot(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,o=n.querySelector(".sub-power-value");o&&(o.innerHTML=`${je(i)} ${qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=o.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");yt(e,t,r,s?.has(i)?ht(s.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const o=t.states[e];if(o){let e;if(t.formatEntityState)e=t.formatEntityState(o);else{e=o.state;const t=o.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(o.attributes.unit_of_measurement||"")){const t=parseFloat(o.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const o=t.querySelector(".slide-confirm");if(!o||!o.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const s=i.closest("[data-uuid]");if(!s||!this._topology||!this._hass)return;const a=s.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,i.classList.contains("panel-gear"))return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings});const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){await this.monitoringCache.fetch(this._hass,this._configEntryId);const t=e.entities?.current??e.entities?.power,n=t?this.monitoringCache.status?.circuits?.[t]??null:null;await this.graphSettingsCache.fetch(this._hass,this._configEntryId);const i=this.graphSettingsCache.settings,r=i?.global_horizon??o,l=i?.circuits?.[a],c=l?{...l,globalHorizon:r}:{horizon:r,has_override:!1,globalHorizon:r};return void s.open({...e,uuid:a,monitoringInfo:n,showMonitoring:this._showMonitoring,graphHorizonInfo:c})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r];await this.graphSettingsCache.fetch(this._hass,this._configEntryId);const t=this.graphSettingsCache.settings,n=t?.global_horizon??o,i=t?.sub_devices?.[r],a=i?{...i,globalHorizon:n}:{horizon:n,has_override:!1,globalHorizon:n};s.open({subDeviceMode:!0,subDeviceId:r,name:e.name??r,deviceType:e.type??"",graphHorizonInfo:a})}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let o=!1,s=0,a=0;const r=t=>{e.classList.contains("confirmed")||(o=!0,s=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!o)return;const t=Math.max(2,Math.min(e-s,a));n.style.left=t+"px"},c=()=>{if(!o)return;o=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Et="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class kt{constructor(){this._ctrl=new Ct,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}async render(e,t,i,o,s){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Oe(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${De(t.message)}

`)}this._ctrl.init(a,o,t,s??null),await this._ctrl.monitoringCache.fetch(t,s??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),h=this._ctrl.monitoringCache.status,p=function(e,t){const i=De(e.device_name||n("header.default_name")),o=De(e.serial||""),s=De(e.firmware||""),a="current"===(t.chart_metric||"power"),r=!!e.panel_entities?.site_power,l=!!e.panel_entities?.dsm_state,c=!!e.panel_entities?.current_power,d=!!e.panel_entities?.feedthrough_power,h=!!e.panel_entities?.pv_power,p=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${i}

\n ${o}\n \n
\n ${n("header.enable_switches")}\n
\n \n
\n
\n
\n
\n ${r?`\n
\n ${n("header.site")}\n
\n 0\n ${a?"A":"kW"}\n
\n
`:""}\n ${l?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${c?`\n
\n ${n("header.upstream")}\n
\n --\n ${a?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.downstream")}\n
\n --\n ${a?"A":"kW"}\n
\n
`:""}\n ${h?`\n
\n ${n("header.solar")}\n
\n --\n ${a?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${s}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}(a,o),u=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),o=[...t,...i],s=o.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=o.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=o.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${s>0?`${s} ${n(s>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(h),g=function(e,t,n,i,o){const s=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),o=1===e.length?"single":We(e)??"single";s.set(i,{uuid:t,circuit:n,layout:o});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of s)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ge(Math.max(...n));0===Fe(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=o?Je(o,t??""):null;let s;if(e.circuit.always_on)s="always_on";else{const t=e.circuit.entities?.select;s=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:s}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,o=2*e,h=s.get(t),p=s.get(o);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:s}=c(h);d+=Ke(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,s),d+=`
${o}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ze(e,"2"));else{const{monInfo:t,sheddingPriority:o}=c(h);d+=Ke(h.uuid,h.circuit,e,"2",h.layout,n,i,t,o)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(o)||(d+=Ze(e,"3"));else{const{monInfo:t,sheddingPriority:o}=c(p);d+=Ke(p.uuid,p.circuit,e,"3",p.layout,n,i,t,o)}d+=`
${o}
`}return d}(a,l,t,o,h),f=function(e,t,i){const o=!1!==i.show_battery,s=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!o||e.type===d&&!s));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,o]of a){const s=o.type===d?n("subdevice.ev_charger"):o.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=ot(o),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=o.type===c,_=o.type===d,f=g?st(o):null,m=g?at(o):null,b=g?rt(o):null,v=lt(o,t,i,new Set([a,f,m,b].filter(e=>null!==e))),y=ct(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${De(s)}\n ${De(o.name||"")}\n ${a?`${je(u)} ${qe(u)}`:""}\n \n
\n ${y}\n ${v}\n
\n `}return h}(a,t,o);e.innerHTML=`\n \n ${p}\n ${u}\n ${f?`
${f}
`:""}\n ${!1!==o.show_panel?`\n
\n ${g}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const m=e.querySelector(".slide-confirm");m&&(this._ctrl.bindSlideConfirm(m,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const zt="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",At="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Pt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Mt="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",Tt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function Nt(e,t,n,i,o){return`\n ${i}\n `}class Dt{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i){let o;void 0!==i&&(this._configEntryId=i),this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const s=o?.global_settings??{},r=!0===o?.enabled,l=o?.circuits??{},c=o?.mains??{},d=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&d.add(e);const h=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))h.has(e)||d.add(`notify.${e}`);d.add("event_bus");const p=[...d].sort(),u=s.notify_targets??"",g=("string"==typeof u?u.split(","):u).map(e=>e.trim()).filter(Boolean),_=p.length>0&&p.every(e=>g.includes(e)),f=s.notification_title_template??"SPAN: {name} {alert_type}",m=s.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=s.notification_priority??"default",v=Object.entries(l).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),y=Object.entries(c),w=[...v,...y],x=w.length>0&&w.every(([,e])=>!1!==e.monitoring_enabled),$=w.some(([,e])=>!1!==e.monitoring_enabled),S=v.map(([e,t])=>{const i=De(t.name??e),o=!1!==t.monitoring_enabled,s=!0===t.has_override,a=o?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Nt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${Nt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${Nt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${Nt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${s?``:""}\n \n \n `}).join(""),C=Object.entries(c).map(([e,t])=>{const i=De(t.name??e),o=!1!==t.monitoring_enabled,s=!0===t.has_override,a=o?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Nt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${Nt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${Nt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${Nt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${s?``:""}\n \n \n `}).join("");e.innerHTML=`\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===p.length?`
${n("notification.no_targets")}
`:p.map(e=>{const i=g.includes(e),o="event_bus"===e,s=o?null:t.states[e],a=s?.attributes?.friendly_name,r=o?n("notification.event_bus_target"):a?`${De(a)} (${De(e)})`:De(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${C}\n ${S}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const E=e.querySelector("#toggle-all-circuits");E&&!x&&$&&(E.indeterminate=!0);const k=e.querySelector("#notify-all-targets");if(k&&p.length>0){const e=g.length>0;!_&&e&&(k.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,l,c),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),o=e.querySelector("#global-fields"),s=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(s){const t=e instanceof Error?e.message:n("error.failed_save");s.textContent=`${n("error.prefix")} ${t}`,s.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const s=i.checked;o&&(o.style.opacity=s?"":"0.4",o.style.pointerEvents=s?"":"none");const a=e.querySelector("#global-status");try{if(s){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),o=e.querySelector("#notify-target-dropdown"),s=e.querySelector("#notify-target-label");if(!i||!o)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==o.style.display;o.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(o.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(s){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);s.textContent=e.length?e.join(", "):n("notification.none_selected")}const o=e.querySelector("#notify-all-targets");if(o){const t=[...e.querySelectorAll(".notify-target-cb")];o.checked=t.length>0&&t.every(e=>e.checked),o.indeterminate=!o.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(o.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),o=e.querySelector("#g-title-template"),s=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),o&&o.addEventListener("input",()=>{r("notification_title_template",o.value)}),s&&s.addEventListener("input",()=>{r("notification_message_template",s.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const o={};this._configEntryId&&(o.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:o}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const o=e.querySelector("#toggle-all-circuits");o&&o.addEventListener("change",async()=>{const s=o.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:s})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:s})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,o=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:o})})}catch{return void(n.checked=!o)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,o=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:o})})}catch{return void(n.checked=!o)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const o=`${i.dataset.entity}-${i.dataset.field}`,s=n.get(o);s&&clearTimeout(s),n.set(o,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const o=i.dataset.entity,s=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:o,[s]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const o=n.dataset.type,s="mains"===o?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===o?{leg:i}:{circuit_id:i});await t.callService(a,s,r),await this.render(e,t)})}}function Lt(e=""){const t=e?` value="${De(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Ht(e){const t="current"===(e.chart_metric||"power");return`\n
\n \n \n
\n `}function It(e,t,i,o,s,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,m=f?`${Math.round(f)}A`:"",b=De(t.name||n("grid.unknown")),v=Be(o),y="current"===v.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,o=n&&parseFloat(n.state)||0;w=`${v.format(o)}A`}else w=`${je(h)}${qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=s?.utilization_pct){const e=s.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${b}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Ot(e,t,n,i,o,s){const a=Ke(e,t,0,"1","single",n,i,o,s,!0);return`
${a}
`}function Rt(e){return`
${De(e)}
`}function qt(e,t,n){const i=e.entities?.switch,o=i?t.states[i]:null,s=e.entities?.power,a=s?t.states[s]:null,l=o?"on"===o.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Ut(e,t,n){return e.sort((e,i)=>{const o=qt(e[1],t,n),s=qt(i[1],t,n);return o.isOn&&!s.isOn?-1:!o.isOn&&s.isOn?1:s.value-o.value})}function Gt(e){return e.entities?.current??e.entities?.power??""}class Ft{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._ctrl=e}renderActivityView(e,t,n,i,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=o;const s=Ut(Object.entries(n.circuits),t,i);let a=Lt(this._searchQuery)+Ht(i);a+='
';for(const[e,n]of s){const s=Je(o,Gt(n)),r=jt(n,t),l=this._expandedUuids.has(e);a+=It(e,n,t,i,s,r,l),l&&(a+=Ot(e,n,t,i,s,r))}a+="
",a+="",e.innerHTML=a;const r=e.querySelector("span-side-panel");r&&(r.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,o,s){this._unbindEvents(),this._hass=t,this._topology=i,this._config=o,this._monitoringStatus=s;const a=n("list.unassigned_area"),r=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??a,i=r.get(n);i?i.push([e,t]):r.set(n,[[e,t]])}const l=[...r.keys()].sort((e,t)=>e===a?1:t===a?-1:e.localeCompare(t));let c=Lt(this._searchQuery)+Ht(o);c+='
';for(const e of l){const n=r.get(e);if(!n)continue;const i=Ut(n,t,o);c+=Rt(e);for(const[e,n]of i){const i=Je(s,Gt(n)),a=jt(n,t),r=this._expandedUuids.has(e);c+=It(e,n,t,o,i,a,r),r&&(c+=Ot(e,n,t,o,i,a))}}c+="
",c+="",e.innerHTML=c;const d=e.querySelector("span-side-panel");d&&(d.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const o=Be(i),s="current"===o.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(s)d.innerHTML=`${o.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${je(i)}${qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),this._expandedUuids.clear(),this._searchQuery="",this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const o=n.closest(".unit-btn");if(o){const t=o.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e))},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const o=t.dataset.rowUuid;if(o){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${o}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t)if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const o=Je(this._monitoringStatus,Gt(i)),s=jt(i,this._hass),a=Ot(e,i,this._hass,this._config,o,s);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}}}let Wt=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._dashboardTab=new kt,this._monitoringTab=new Dt,this._listDashCtrl=new Ct,this._listCtrl=new Ft(this._listDashCtrl),this._areaUnsub=null,this._onVisibilityChange=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass;const n=this.renderRoot.querySelector("ha-menu-button");n&&(n.hass=this.hass,n.narrow=this.narrow),this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(e.has("narrow")){const e=this.renderRoot.querySelector("ha-menu-button");e&&(e.narrow=this.narrow)}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var i,o,s;return i=this.hass?.language,e=i&&t[i]?i:"en",this._discovered?se` + */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}async function Fe(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}async function He(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}class Oe{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Re(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const qe=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);function je(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Ue extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Fe(this._hass,i):await He(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=je(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Fe(this._hass,t):await He(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=je(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i=t.subDeviceId;"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:i}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of qe){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ue)}catch{}async function Ge(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function Ve(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ge(e,i),{topology:i,panelDevice:r,panelSize:s}}function We(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Be=u.power;function Qe(e){return Be.unit(e)}function Je(e){return(e<0?"-":"")+Be.format(e)}function Xe(e){return(Math.abs(e)/1e3).toFixed(1)}function Ke(e){return Math.ceil(e/2)}function Ze(e){return e%2==0?1:0}function Ye(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ke(t)===Ke(n)?"row-span":Ze(t)===Ze(n)?"col-span":"row-span"}function et(e){const t=e.chart_metric??i;return u[t]??u[i]}function tt(e,t){const n=function(e){return et(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class nt{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function it(e,t){return e?.circuits?e.circuits[t]??null:null}function st(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function ot(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=et(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${Je(v)}${Qe(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function at(e,t){return`\n
\n \n
\n `}const rt={names:["power","battery power"],suffixes:["_power"]},lt={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},ct={names:["state of energy"],suffixes:["_soe_kwh"]},dt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function ht(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function pt(e){return ht(e,rt)}function ut(e){return ht(e,lt)}function gt(e){return ht(e,ct)}function _t(e){return ht(e,dt)}function ft(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=pt(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?ut(s):null,v=g?gt(s):null,m=g?_t(s):null,b=vt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=mt(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${Je(u)} ${Qe(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function vt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function mt(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function bt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function yt(e){const t=o[e];return t?t.ms:o[s].ms}function wt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function xt(e){return Math.max(500,Math.floor(e/5e3))}function $t(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function St(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function Ct(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function Et(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=wt(i),l=xt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,St(t,r,l))}}}function kt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:pt(i)};i.type===c&&(e.soc=ut(i),e.soe=gt(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function zt(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=tt(i,n);if(!t)continue;let o;o=s&&s.has(e)?yt(s.get(e)):bt(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of kt(t)){let t;t=o&&o.has(s)?yt(o.get(s)):bt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(Ct(e,n.entityIds,n.uuidByEntity,t,i)):r.push(Et(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function At(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function Pt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=bt(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Xe(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Xe(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Xe(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Xe(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=et(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${Je(f)}${Qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?yt(a.get(s)):c,p=d.device_type===l;At(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class Mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function Tt(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function It(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Nt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new nt,this.graphSettingsCache=new Mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,Tt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,It(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await zt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=tt(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=yt(i),d=wt(c),h=xt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of kt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await zt(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(Pt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=bt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=pt(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${Je(i)} ${Qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");At(e,t,r,o?.has(i)?yt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Dt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class Lt{constructor(){this._ctrl=new Nt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Ve(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=We(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ye(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ke(Math.max(...n));0===Ze(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?it(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=ot(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=at(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=ot(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=at(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=ot(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ft(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Ft="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Ot="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Rt="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",qt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function jt(e,t,n,i,s){return`\n ${i}\n `}class Ut{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function Gt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Vt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=et(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Je(h)}${Qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Wt(e,t,n,i,s,o){const a=ot(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Bt(e){return`
${Ne(e)}
`}function Qt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Xt(e,t,n){return e.sort((e,i)=>{const s=Qt(e[1],t,n),o=Qt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Kt(e){return e.entities?.current??e.entities?.power??""}class Zt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Xt(Object.entries(n.circuits),t,i);let r=o+Gt(this._searchQuery);r+='
';for(const[e,n]of a){const o=it(s,Kt(n)),a=Jt(n,t),l=this._expandedUuids.has(e);r+=Vt(e,n,t,i,o,a,l),l&&(r+=Wt(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+Gt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Xt(n,t,s);d+=Bt(e);for(const[e,n]of i){const i=it(o,Kt(n)),a=Jt(n,t),r=this._expandedUuids.has(e);d+=Vt(e,n,t,s,i,a,r),r&&(d+=Wt(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=et(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${Je(i)}${Qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=it(this._monitoringStatus,Kt(i)),o=Jt(i,this._hass),a=Wt(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Yt(e,t){return`${e}|${t}`}class en{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await Ve(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Yt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Yt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const tn="favorites",nn="span_panel_favorites_view_state";function sn(e){try{localStorage.setItem(nn,JSON.stringify(e))}catch{}}let on=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new Lt,this._monitoringTab=new Ut,this._listDashCtrl=new Nt,this._listCtrl=new Zt(this._listDashCtrl),this._favCache=new Oe,this._favCtrl=new en,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe`
- +
-
- ${Te((o=[{id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}],s=this._activeTab,`
${o.map(e=>``).join("")}
`))} -
+
${Te((i=this._buildTabList(),s=this._activeTab,`
${i.map(e=>``).join("")}
`))}
@@ -74,20 +72,30 @@ const Ce={attribute:!0,type:String,converter:L,reflect:!1,hasChanged:H},Ee=(e=Ce @side-panel-closed=${this._onSidePanelClosed} @graph-settings-changed=${this._onGraphSettingsChanged} @navigate-tab=${this._onNavigateTab} + @favorites-view-state-changed=${this._onFavoritesViewStateChangedEvent} >
- `:se` + `:oe`
- +
Span Panel
${this._discoveryError??"Loading…"}
- `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.map(e=>e.id)),n=new Set(e.map(e=>e.id));t.size===n.size&&[...t].every(e=>n.has(e))||(this._panels=e,!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0&&(this._selectedPanelId=this._panels[0].id,localStorage.setItem("span_panel_selected",this._selectedPanelId)))}async _discoverPanels(){if(!this.hass)return;try{const e=await this.hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._discoveryError=null,this._discovered=!0;const e=localStorage.getItem("span_panel_selected");e&&this._panels.some(t=>t.id===e)?this._selectedPanelId=e:this._panels.length>0&&(this._selectedPanelId=this._panels[0].id),this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();const e=this.shadowRoot.getElementById("tab-content");if(e)switch(this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Oe(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps(),this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Oe(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps(),this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await Ie(e,t);for(const[e,o]of Object.entries(t.circuits))if(o.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[o,s]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{o(),s()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}};Wt.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` + `:oe` +
+
+
Span Panel
+
+
+
+
${"Loading…"}
+
+ `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===tn}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,sn(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,sn(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==tn).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(nn);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===tn){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Re(t))return e;return[{id:tn,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){this._favCache.invalidate();const e=await this._loadFavorites(),t=this._selectedPanelId===tn;this._favorites=e;const n=this._panels.filter(e=>e.id!==tn);if(this._panels=this._buildPanelList(n,e),t&&!Re(e)){!function(){try{localStorage.removeItem(nn)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView||this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return We(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=Object.values(this._favorites).filter(e=>(e.circuits?.length??0)>0||(e.sub_devices?.length??0)>0).length,t=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),i=n(1===t?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(t)).replace("{panels}",String(e)),s="current"===(this._chartMetric||"power");return`\n
\n
${Ne(n("panel.favorites"))}
\n
${Ne(i)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await Ge(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==tn),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ft(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const o=document.createElement("h3");o.style.margin="8px 0 12px",o.style.fontSize="1em",o.textContent=t?.name_by_user??t?.name??e,n.appendChild(o);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const r=new Ut;this._favoritesMonitoringTabs.set(e,r),await r.render(a,this.hass,e)}}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};on.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` :host { color: var(--primary-text-color); } @@ -177,4 +185,4 @@ const Ce={attribute:!0,type:String,converter:L,reflect:!1,hasChanged:H},Ee=(e=Ce opacity: 1; border-bottom-color: var(--app-header-text-color, white); } - `,m([ke({attribute:!1})],Wt.prototype,"hass",void 0),m([ke({type:Boolean,reflect:!0})],Wt.prototype,"narrow",void 0),m([ze()],Wt.prototype,"_panels",void 0),m([ze()],Wt.prototype,"_selectedPanelId",void 0),m([ze()],Wt.prototype,"_activeTab",void 0),m([ze()],Wt.prototype,"_discovered",void 0),m([ze()],Wt.prototype,"_discoveryError",void 0),m([ze()],Wt.prototype,"_chartMetric",void 0),Wt=m([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],Wt),console.warn("%c SPAN-PANEL %c v0.9.2 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let Bt=!1;const Vt=Wt.prototype.connectedCallback;Wt.prototype.connectedCallback=function(){Bt=!0,Vt.call(this)};const Qt=Wt.prototype.disconnectedCallback;Wt.prototype.disconnectedCallback=function(){Bt=!1,Qt.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(Bt||window.location.pathname.includes("span-panel")&&setTimeout(()=>{Bt||location.reload()},200))}); + `,v([ke({attribute:!1})],on.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],on.prototype,"narrow",void 0),v([ze()],on.prototype,"_panels",void 0),v([ze()],on.prototype,"_selectedPanelId",void 0),v([ze()],on.prototype,"_activeTab",void 0),v([ze()],on.prototype,"_discovered",void 0),v([ze()],on.prototype,"_discoveryError",void 0),v([ze()],on.prototype,"_chartMetric",void 0),v([ze()],on.prototype,"_favorites",void 0),on=v([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],on),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let an=!1;const rn=on.prototype.connectedCallback;on.prototype.connectedCallback=function(){an=!0,rn.call(this)};const ln=on.prototype.disconnectedCallback;on.prototype.disconnectedCallback=function(){an=!1,ln.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(an||window.location.pathname.includes("span-panel")&&setTimeout(()=>{an||location.reload()},200))}); diff --git a/package.json b/package.json index 00cb3d2..aeabfa9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "span-panel-card", - "version": "0.9.2", + "version": "0.9.3", "private": true, "type": "module", "scripts": { diff --git a/src/card/span-panel-card.ts b/src/card/span-panel-card.ts index 1888d8c..1951f72 100644 --- a/src/card/span-panel-card.ts +++ b/src/card/span-panel-card.ts @@ -338,11 +338,13 @@ export class SpanPanelCard extends LitElement { this._ctrl.setupResizeObserver(this.shadowRoot!, this.shadowRoot!.querySelector("ha-card")); } else if (this._activeTab === "activity") { container.innerHTML = ""; - this._listCtrl.renderActivityView(container as HTMLElement, this.hass, this._topology, this._config, this._ctrl.monitoringCache.status); + const listHeaderHTML = buildHeaderHTML(this._topology, this._config, { showSwitches: false }); + this._listCtrl.renderActivityView(container as HTMLElement, this.hass, this._topology, this._config, this._ctrl.monitoringCache.status, listHeaderHTML); this._ctrl.updateDOM(this.shadowRoot!); } else if (this._activeTab === "area") { container.innerHTML = ""; - this._listCtrl.renderAreaView(container as HTMLElement, this.hass, this._topology, this._config, this._ctrl.monitoringCache.status); + const listHeaderHTML = buildHeaderHTML(this._topology, this._config, { showSwitches: false }); + this._listCtrl.renderAreaView(container as HTMLElement, this.hass, this._topology, this._config, this._ctrl.monitoringCache.status, listHeaderHTML); this._ctrl.updateDOM(this.shadowRoot!); } } diff --git a/src/constants.ts b/src/constants.ts index ffcb6c1..581786f 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,7 +1,7 @@ import { t } from "./i18n.js"; import type { ChartMetricDef, GraphHorizonPreset, SheddingPriorityDef } from "./types.js"; -export const CARD_VERSION = "0.9.2"; +export const CARD_VERSION = "0.9.3"; // -- Defaults -- diff --git a/src/core/dashboard-controller.ts b/src/core/dashboard-controller.ts index 9e5436d..53e915a 100644 --- a/src/core/dashboard-controller.ts +++ b/src/core/dashboard-controller.ts @@ -1,4 +1,4 @@ -import { DEFAULT_GRAPH_HORIZON, GRAPH_HORIZONS, LIVE_SAMPLE_INTERVAL_MS } from "../constants.js"; +import { DEFAULT_GRAPH_HORIZON, GRAPH_HORIZONS, INTEGRATION_DOMAIN, LIVE_SAMPLE_INTERVAL_MS } from "../constants.js"; import { getCircuitChartEntity } from "../helpers/chart.js"; import { getHorizonDurationMs, getMaxHistoryPoints, getMinGapMs, recordSample } from "../helpers/history.js"; import { loadHistory, collectSubDeviceEntityIds } from "./history-loader.js"; @@ -6,7 +6,7 @@ import { updateCircuitDOM, updateSubDeviceDOM } from "./dom-updater.js"; import { getEffectiveHorizon, getEffectiveSubDeviceHorizon } from "./graph-settings.js"; import { MonitoringStatusCache } from "./monitoring-status.js"; import { GraphSettingsCache } from "./graph-settings.js"; -import type { HomeAssistant, PanelTopology, CardConfig, HistoryMap, GraphSettings } from "../types.js"; +import type { CardConfig, FavoriteRef, GraphSettings, HistoryMap, HomeAssistant, MonitoringStatus, MonitoringStatusResponse, PanelTopology } from "../types.js"; const RECORDER_REFRESH_MS = 30_000; const RESIZE_THRESHOLD_PX = 5; @@ -36,6 +36,26 @@ export class DashboardController { private _config: CardConfig | null = null; private _configEntryId: string | null = null; + /** + * Set when rendering the Favorites pseudo-panel. Composite circuit + * ids (``"{panelDeviceId}|{circuitUuid}"``) resolve through this map + * to the originating panel so side-panel edits target the correct + * config entry. ``null`` means normal single-panel mode. + */ + private _favRefs: Record | null = null; + + /** + * Context used when opening the panel-mode side panel (Graph Settings) + * on a single real panel: the panel's HA device id plus the subsets + * of circuit uuids and sub-device HA device ids the user has favorited. + * Populated by the dashboard wrapper before tab renders. + */ + private _panelFavorites: { + panelDeviceId: string; + circuitUuids: Set; + subDeviceIds: Set; + } | null = null; + private _showMonitoring = false; private _updateInterval: ReturnType | null = null; private _recorderRefreshInterval: ReturnType | null = null; @@ -70,6 +90,41 @@ export class DashboardController { this._configEntryId = configEntryId; } + /** + * Enter Favorites-view mode. ``refs`` maps the composite circuit ids + * present in the merged topology to their originating panel + circuit + * uuid + config entry. ``favoriteIds`` is the subset currently marked + * (effectively the keys of ``refs`` for this view, kept as a Set for + * fast heart-state lookups in panel-mode). + */ + setFavoriteRefs(refs: Record): void { + this._favRefs = refs; + } + + clearFavoriteRefs(): void { + this._favRefs = null; + } + + /** + * Provide the current panel's favorited circuit uuids and sub-device + * ids. Used only when opening the panel-mode (Graph Settings) side + * panel so its per-target list can render filled/outlined heart + * toggles. Pass ``null`` to disable hearts (e.g. standalone card). + */ + setPanelFavorites( + info: { + panelDeviceId: string; + circuitUuids: Set; + subDeviceIds: Set; + } | null + ): void { + this._panelFavorites = info; + } + + private get _inFavoritesView(): boolean { + return this._favRefs !== null; + } + setConfig(config: CardConfig): void { this._config = config; } @@ -260,11 +315,19 @@ export class DashboardController { sidePanel.hass = this._hass; if (gearBtn.classList.contains("panel-gear")) { + // Favorites view has no single panel to configure — the aggregate + // doesn't own global horizon or other panel-level settings. + if (this._inFavoritesView) return; await this.graphSettingsCache.fetch(this._hass, this._configEntryId); sidePanel.open({ panelMode: true, topology: this._topology, graphSettings: this.graphSettingsCache.settings, + showFavorites: this._panelFavorites !== null, + favoritePanelDeviceId: this._panelFavorites?.panelDeviceId, + favoriteCircuitUuids: this._panelFavorites?.circuitUuids, + favoriteSubDeviceIds: this._panelFavorites?.subDeviceIds, + configEntryId: this._configEntryId, }); return; } @@ -273,22 +336,47 @@ export class DashboardController { if (uuid && this._topology) { const circuit = this._topology.circuits[uuid]; if (circuit) { - await this.monitoringCache.fetch(this._hass, this._configEntryId); + const ref = this._favRefs?.[uuid] ?? null; + const realUuid = ref && ref.kind === "circuit" ? ref.targetId : uuid; + const entryId = ref?.configEntryId ?? this._configEntryId; + + // In favorites view, bypass the single-entry caches so we pick + // up the right panel's current graph/monitoring state. + let graphSettings: GraphSettings | null; + let monitoringStatus: MonitoringStatus | null; + if (ref) { + [graphSettings, monitoringStatus] = await Promise.all([this._fetchGraphSettingsFresh(entryId), this._fetchMonitoringStatusFresh(entryId)]); + } else { + await Promise.all([this.graphSettingsCache.fetch(this._hass, entryId), this.monitoringCache.fetch(this._hass, entryId)]); + graphSettings = this.graphSettingsCache.settings; + monitoringStatus = this.monitoringCache.status; + } + const monitoringEntity = circuit.entities?.current ?? circuit.entities?.power; - const monitoringInfo = monitoringEntity ? (this.monitoringCache.status?.circuits?.[monitoringEntity] ?? null) : null; + const monitoringInfo = monitoringEntity ? (monitoringStatus?.circuits?.[monitoringEntity] ?? null) : null; - await this.graphSettingsCache.fetch(this._hass, this._configEntryId); - const graphSettings = this.graphSettingsCache.settings; const globalHorizon = graphSettings?.global_horizon ?? DEFAULT_GRAPH_HORIZON; - const circuitOverride = graphSettings?.circuits?.[uuid]; + const circuitOverride = graphSettings?.circuits?.[realUuid]; const graphHorizonInfo = circuitOverride ? { ...circuitOverride, globalHorizon } : { horizon: globalHorizon, has_override: false, globalHorizon }; + // Heart section shows whenever we're in a dashboard context — either + // the Favorites pseudo-panel (always favorited) or a real panel with + // the per-panel favorites set supplied by span-panel.ts. Standalone + // omits both and hearts don't render. + const favoritePanelDeviceId = ref?.panelDeviceId ?? this._panelFavorites?.panelDeviceId; + const isFavorite = ref !== null || (this._panelFavorites?.circuitUuids.has(realUuid) ?? false); + const showFavorites = this._inFavoritesView || this._panelFavorites !== null; + sidePanel.open({ ...circuit, - uuid, + uuid: realUuid, monitoringInfo, showMonitoring: this._showMonitoring, graphHorizonInfo, + showFavorites, + favoritePanelDeviceId, + isFavorite, + configEntryId: entryId, } as Record); return; } @@ -297,20 +385,81 @@ export class DashboardController { const subDevId = gearBtn.dataset.subdevId; if (subDevId && this._topology?.sub_devices?.[subDevId]) { const sub = this._topology.sub_devices[subDevId]!; + const ref = this._favRefs?.[subDevId] ?? null; + const realSubDevId = ref && ref.kind === "sub_device" ? ref.targetId : subDevId; + const entryId = ref?.configEntryId ?? this._configEntryId; + + let graphSettings: GraphSettings | null; + if (ref) { + graphSettings = await this._fetchGraphSettingsFresh(entryId); + } else { + await this.graphSettingsCache.fetch(this._hass, entryId); + graphSettings = this.graphSettingsCache.settings; + } - await this.graphSettingsCache.fetch(this._hass, this._configEntryId); - const graphSettings = this.graphSettingsCache.settings; const globalHorizon = graphSettings?.global_horizon ?? DEFAULT_GRAPH_HORIZON; - const subOverride = graphSettings?.sub_devices?.[subDevId]; + const subOverride = graphSettings?.sub_devices?.[realSubDevId]; const graphHorizonInfo = subOverride ? { ...subOverride, globalHorizon } : { horizon: globalHorizon, has_override: false, globalHorizon }; + const favoritePanelDeviceId = ref?.panelDeviceId ?? this._panelFavorites?.panelDeviceId; + const isFavorite = ref !== null || (this._panelFavorites?.subDeviceIds.has(realSubDevId) ?? false); + const showFavorites = this._inFavoritesView || this._panelFavorites !== null; + sidePanel.open({ subDeviceMode: true, - subDeviceId: subDevId, - name: sub.name ?? subDevId, + subDeviceId: realSubDevId, + name: sub.name ?? realSubDevId, deviceType: sub.type ?? "", + entities: sub.entities, graphHorizonInfo, + showFavorites, + favoritePanelDeviceId, + isFavorite, + configEntryId: entryId, + }); + } + } + + /** + * Uncached fetch of graph settings for a specific config entry. + * Used in Favorites view where the shared ``graphSettingsCache`` is + * keyed to a different (primary) entry. + */ + private async _fetchGraphSettingsFresh(entryId: string | null): Promise { + if (!this._hass) return null; + try { + const serviceData: Record = {}; + if (entryId) serviceData.config_entry_id = entryId; + const resp = await this._hass.callWS<{ response?: GraphSettings }>({ + type: "call_service", + domain: INTEGRATION_DOMAIN, + service: "get_graph_settings", + service_data: serviceData, + return_response: true, }); + return resp?.response ?? null; + } catch { + return null; + } + } + + private async _fetchMonitoringStatusFresh(entryId: string | null): Promise { + if (!this._hass) return null; + try { + const serviceData: Record = {}; + if (entryId) serviceData.config_entry_id = entryId; + const resp = await this._hass.callWS<{ response?: MonitoringStatusResponse }>({ + type: "call_service", + domain: INTEGRATION_DOMAIN, + service: "get_monitoring_status", + service_data: serviceData, + return_response: true, + }); + const response = resp?.response; + if (!response) return null; + return { circuits: response.circuits, mains: response.mains }; + } catch { + return null; } } diff --git a/src/core/favorites-controller.ts b/src/core/favorites-controller.ts new file mode 100644 index 0000000..6529c81 --- /dev/null +++ b/src/core/favorites-controller.ts @@ -0,0 +1,136 @@ +// src/core/favorites-controller.ts +import { discoverTopology } from "../card/card-discovery.js"; +import type { FavoriteRef, FavoritesMap, FavoritesTopology, HomeAssistant, PanelDevice, PanelTopology } from "../types.js"; + +const COMPOSITE_SEPARATOR = "|"; + +/** Build the composite circuit id used by the Favorites view. */ +export function buildCompositeId(panelDeviceId: string, circuitUuid: string): string { + return `${panelDeviceId}${COMPOSITE_SEPARATOR}${circuitUuid}`; +} + +/** + * Parse a composite id back into its ``(panelDeviceId, circuitUuid)`` + * parts. Returns ``null`` when the input is not a composite id — callers + * should treat a plain uuid as "use the current panel" in that case. + */ +export function parseCompositeId(id: string): { panelDeviceId: string; circuitUuid: string } | null { + const idx = id.indexOf(COMPOSITE_SEPARATOR); + if (idx <= 0 || idx === id.length - 1) return null; + return { + panelDeviceId: id.slice(0, idx), + circuitUuid: id.slice(idx + 1), + }; +} + +export interface FavoritesBuildResult { + topology: FavoritesTopology; + /** Unique contributing config entry ids (for monitoring tab stacking). */ + entryIds: string[]; + /** + * Per-panel raw topologies, keyed by panel device id. Callers that + * need to resolve a composite id to a real circuit (e.g. the side + * panel's gear routing) can look up the originating topology here. + */ + panelTopologies: Record; +} + +/** + * Aggregate the topologies of every panel that has at least one + * favorited circuit into a single ``FavoritesTopology``. Circuit keys in + * the merged topology are composite ids so uuids from different panels + * cannot collide; ``_favoriteRefs`` records the origin of each. + */ +export class FavoritesController { + async build(hass: HomeAssistant, favorites: FavoritesMap, panels: PanelDevice[]): Promise { + const panelsById = new Map(); + for (const p of panels) panelsById.set(p.id, p); + + const fetches: Promise<{ + panelDeviceId: string; + panel: PanelDevice; + topology: PanelTopology | null; + }>[] = []; + for (const [panelDeviceId, entry] of Object.entries(favorites)) { + const hasAny = (entry?.circuits?.length ?? 0) > 0 || (entry?.sub_devices?.length ?? 0) > 0; + if (!hasAny) continue; + const panel = panelsById.get(panelDeviceId); + if (!panel) continue; + fetches.push( + (async () => { + try { + const result = await discoverTopology(hass, panelDeviceId); + return { panelDeviceId, panel, topology: result.topology }; + } catch (err) { + console.warn("SPAN Panel: favorites topology fetch failed", panelDeviceId, err); + return { panelDeviceId, panel, topology: null }; + } + })() + ); + } + + const results = await Promise.all(fetches); + const contributing = results.filter(r => r.topology !== null); + const includePanelPrefix = contributing.length > 1; + + const mergedCircuits: FavoritesTopology["circuits"] = {}; + const mergedSubDevices: NonNullable = {}; + const refs: Record = {}; + const panelTopologies: Record = {}; + const entryIds = new Set(); + + for (const { panelDeviceId, panel, topology } of contributing) { + if (!topology) continue; + panelTopologies[panelDeviceId] = topology; + const configEntryId = panel.config_entries?.[0] ?? null; + if (configEntryId) entryIds.add(configEntryId); + + const panelLabel = panel.name_by_user ?? panel.name ?? topology.device_name ?? ""; + const entry = favorites[panelDeviceId]; + const favoriteCircuitUuids = entry?.circuits ?? []; + const favoriteSubDeviceIds = entry?.sub_devices ?? []; + + for (const uuid of favoriteCircuitUuids) { + const circuit = topology.circuits?.[uuid]; + if (!circuit) continue; + const compositeId = buildCompositeId(panelDeviceId, uuid); + const name = includePanelPrefix && panelLabel ? `${panelLabel} \u00b7 ${circuit.name}` : circuit.name; + mergedCircuits[compositeId] = { ...circuit, name }; + refs[compositeId] = { + panelDeviceId, + kind: "circuit", + targetId: uuid, + configEntryId, + }; + } + + for (const subDevId of favoriteSubDeviceIds) { + const sub = topology.sub_devices?.[subDevId]; + if (!sub) continue; + const compositeId = buildCompositeId(panelDeviceId, subDevId); + const name = includePanelPrefix && panelLabel && sub.name ? `${panelLabel} \u00b7 ${sub.name}` : (sub.name ?? subDevId); + mergedSubDevices[compositeId] = { ...sub, name }; + refs[compositeId] = { + panelDeviceId, + kind: "sub_device", + targetId: subDevId, + configEntryId, + }; + } + } + + const topology: FavoritesTopology = { + circuits: mergedCircuits, + sub_devices: mergedSubDevices, + panel_entities: {}, + device_name: "", + _favoriteRefs: refs, + }; + + return { + topology, + entryIds: Array.from(entryIds), + panelTopologies, + }; + } +} diff --git a/src/core/favorites-store.ts b/src/core/favorites-store.ts new file mode 100644 index 0000000..5241756 --- /dev/null +++ b/src/core/favorites-store.ts @@ -0,0 +1,142 @@ +// src/core/favorites-store.ts +import { INTEGRATION_DOMAIN } from "../constants.js"; +import type { FavoritesMap, HomeAssistant } from "../types.js"; + +const FAVORITES_POLL_INTERVAL_MS = 30_000; + +/** + * Event dispatched on ``document`` when favorites have been mutated by + * any side-panel toggle. Consumers (e.g. the dashboard panel) listen to + * refresh their synthetic Favorites entry. + */ +export const FAVORITES_CHANGED_EVENT = "favorites-changed"; + +interface GetFavoritesResponse { + favorites?: FavoritesMap; +} + +interface CallServiceResponse { + response?: T; +} + +async function _callFavoritesService(hass: HomeAssistant, service: string, serviceData: Record = {}): Promise { + const resp = await hass.callWS>({ + type: "call_service", + domain: INTEGRATION_DOMAIN, + service, + service_data: serviceData, + return_response: true, + }); + return resp?.response ?? null; +} + +/** + * Fetch the current favorites map from the HA backend. Always hits the + * backend; callers should prefer ``FavoritesCache.fetch`` when they want + * request coalescing. + */ +export async function fetchFavorites(hass: HomeAssistant): Promise { + const resp = await _callFavoritesService(hass, "get_favorites"); + return resp?.favorites ?? {}; +} + +/** + * Mark the entity (a circuit current/power sensor or any sub-device + * sensor) as a favorite. The backend resolves the entity_id to its + * panel + (circuit_uuid | sub_device_id) tuple, so callers never need + * to know storage shapes or internal identifiers. + */ +export async function addFavorite(hass: HomeAssistant, entityId: string): Promise { + const resp = await _callFavoritesService(hass, "add_favorite", { + entity_id: entityId, + }); + document.dispatchEvent(new CustomEvent(FAVORITES_CHANGED_EVENT)); + return resp?.favorites ?? {}; +} + +/** + * Remove the entity from the favorites map. See ``addFavorite`` for the + * reasoning behind the entity_id API. + */ +export async function removeFavorite(hass: HomeAssistant, entityId: string): Promise { + const resp = await _callFavoritesService(hass, "remove_favorite", { + entity_id: entityId, + }); + document.dispatchEvent(new CustomEvent(FAVORITES_CHANGED_EVENT)); + return resp?.favorites ?? {}; +} + +/** + * Cached favorites map with a 30-second TTL and in-flight deduplication. + * Mirrors ``GraphSettingsCache``'s lifecycle so the dashboard panel can + * refresh on events (``invalidate()``) without thrashing the backend. + */ +export class FavoritesCache { + private _map: FavoritesMap | null; + private _lastFetch: number; + private _inflight: Promise | null; + + constructor() { + this._map = null; + this._lastFetch = 0; + this._inflight = null; + } + + async fetch(hass: HomeAssistant): Promise { + const now = Date.now(); + if (this._inflight) return this._inflight; + if (this._map && now - this._lastFetch < FAVORITES_POLL_INTERVAL_MS) { + return this._map; + } + + this._inflight = (async () => { + try { + const map = await fetchFavorites(hass); + this._map = map; + this._lastFetch = Date.now(); + return map; + } catch { + return this._map ?? {}; + } finally { + this._inflight = null; + } + })(); + return this._inflight; + } + + invalidate(): void { + this._lastFetch = 0; + } + + clear(): void { + this._map = null; + this._lastFetch = 0; + } + + get map(): FavoritesMap { + return this._map ?? {}; + } +} + +/** + * Count the total number of favorited targets (circuits + sub-devices) + * across all panels. + */ +export function countFavorites(map: FavoritesMap): number { + let n = 0; + for (const entry of Object.values(map)) { + n += (entry.circuits?.length ?? 0) + (entry.sub_devices?.length ?? 0); + } + return n; +} + +/** + * True when the user has at least one favorite configured (any kind). + */ +export function hasAnyFavorites(map: FavoritesMap): boolean { + for (const entry of Object.values(map)) { + if ((entry.circuits?.length ?? 0) > 0) return true; + if ((entry.sub_devices?.length ?? 0) > 0) return true; + } + return false; +} diff --git a/src/core/header-renderer.ts b/src/core/header-renderer.ts index 0619e05..8875c95 100644 --- a/src/core/header-renderer.ts +++ b/src/core/header-renderer.ts @@ -3,14 +3,24 @@ import { t } from "../i18n.js"; import { SHEDDING_PRIORITIES } from "../constants.js"; import type { PanelTopology, CardConfig, SheddingPriorityDef } from "../types.js"; +export interface HeaderRenderOptions { + /** + * Include the slide-to-enable switches control. Only the By Panel + * tab renders the breaker grid with circuit toggles, so the other + * tabs should omit this control to avoid a non-functional button. + */ + showSwitches?: boolean; +} + /** * Build the panel header HTML with stats, gear icon, and A/W toggle. */ -export function buildHeaderHTML(topology: PanelTopology, config: CardConfig): string { +export function buildHeaderHTML(topology: PanelTopology, config: CardConfig, options: HeaderRenderOptions = {}): string { const panelName: string = escapeHtml(topology.device_name || t("header.default_name")); const serial: string = escapeHtml(topology.serial || ""); const firmware: string = escapeHtml(topology.firmware || ""); const isAmpsMode: boolean = (config.chart_metric || "power") === "current"; + const showSwitches = options.showSwitches !== false; const hasSite: boolean = !!topology.panel_entities?.site_power; const hasGrid: boolean = !!topology.panel_entities?.dsm_state; @@ -28,12 +38,16 @@ export function buildHeaderHTML(topology: PanelTopology, config: CardConfig): st -
+ ${ + showSwitches + ? `
${t("header.enable_switches")}
-
+
` + : "" + }
${ diff --git a/src/core/list-view-controller.ts b/src/core/list-view-controller.ts index 0f151e5..bc42fe1 100644 --- a/src/core/list-view-controller.ts +++ b/src/core/list-view-controller.ts @@ -3,7 +3,7 @@ import { formatPowerSigned, formatPowerUnit } from "../helpers/format.js"; import { getChartMetric } from "../helpers/chart.js"; import { t } from "../i18n.js"; import { getCircuitMonitoringInfo } from "./monitoring-status.js"; -import { buildSearchBarHTML, buildUnitToggleHTML, buildListRowHTML, buildExpandedCircuitHTML, buildAreaHeaderHTML } from "./list-renderer.js"; +import { buildSearchBarHTML, buildListRowHTML, buildExpandedCircuitHTML, buildAreaHeaderHTML } from "./list-renderer.js"; import type { DashboardController } from "./dashboard-controller.js"; import type { HomeAssistant, PanelTopology, CardConfig, Circuit, MonitoringStatus } from "../types.js"; @@ -58,6 +58,14 @@ function getCircuitEntityId(circuit: Circuit): string { return circuit.entities?.current ?? circuit.entities?.power ?? ""; } +export const FAVORITES_VIEW_STATE_CHANGED_EVENT = "favorites-view-state-changed"; + +export interface FavoritesViewStateDetail { + view: "activity" | "area"; + expanded: string[]; + searchQuery: string; +} + export class ListViewController { private _ctrl: DashboardController; private _expandedUuids = new Set(); @@ -73,16 +81,47 @@ export class ListViewController { private _config: CardConfig | null = null; private _monitoringStatus: MonitoringStatus | null = null; + /** + * When set to ``"activity"`` or ``"area"``, expansion and search-box + * mutations dispatch ``favorites-view-state-changed`` so span-panel.ts + * can persist the Favorites pseudo-panel's view state to localStorage. + * ``null`` (the default) disables persistence for real-panel renders. + */ + private _viewName: "activity" | "area" | null = null; + constructor(ctrl: DashboardController) { this._ctrl = ctrl; } + /** + * Seed the expansion set before the next render. Called by + * ``span-panel.ts`` when re-entering the Favorites view so the user's + * previously expanded rows come back. + */ + setInitialExpansion(ids: Iterable): void { + this._expandedUuids = new Set(ids); + } + + /** Seed the search query before the next render. */ + setInitialSearchQuery(query: string): void { + this._searchQuery = query; + } + + /** + * Mark the upcoming render as belonging to a Favorites-view tab so + * that expansion/search state persists across dropdown switches. + */ + setViewName(viewName: "activity" | "area" | null): void { + this._viewName = viewName; + } + renderActivityView( container: HTMLElement, hass: HomeAssistant, topology: PanelTopology, config: CardConfig, - monitoringStatus: MonitoringStatus | null + monitoringStatus: MonitoringStatus | null, + headerHTML: string ): void { this._unbindEvents(); this._hass = hass; @@ -93,7 +132,7 @@ export class ListViewController { const entries: [string, Circuit][] = Object.entries(topology.circuits); const sorted = sortCircuitEntries(entries, hass, config); - let html = buildSearchBarHTML(this._searchQuery) + buildUnitToggleHTML(config); + let html = headerHTML + buildSearchBarHTML(this._searchQuery); html += '
'; for (const [uuid, circuit] of sorted) { @@ -116,7 +155,14 @@ export class ListViewController { this._ctrl.updateDOM(container); } - renderAreaView(container: HTMLElement, hass: HomeAssistant, topology: PanelTopology, config: CardConfig, monitoringStatus: MonitoringStatus | null): void { + renderAreaView( + container: HTMLElement, + hass: HomeAssistant, + topology: PanelTopology, + config: CardConfig, + monitoringStatus: MonitoringStatus | null, + headerHTML: string + ): void { this._unbindEvents(); this._hass = hass; this._topology = topology; @@ -144,7 +190,7 @@ export class ListViewController { return a.localeCompare(b); }); - let html = buildSearchBarHTML(this._searchQuery) + buildUnitToggleHTML(config); + let html = headerHTML + buildSearchBarHTML(this._searchQuery); html += '
'; for (const areaName of areaNames) { @@ -219,14 +265,35 @@ export class ListViewController { stop(): void { this._unbindEvents(); - this._expandedUuids.clear(); - this._searchQuery = ""; + // Only reset user-visible view state for real-panel renders. In the + // Favorites view we preserve expansion/search across re-renders so + // switching tabs or reloading the page restores the user's layout. + if (this._viewName === null) { + this._expandedUuids.clear(); + this._searchQuery = ""; + } this._hass = null; this._topology = null; this._config = null; this._monitoringStatus = null; } + private _dispatchFavoritesViewState(): void { + if (!this._viewName || !this._container) return; + const detail: FavoritesViewStateDetail = { + view: this._viewName, + expanded: [...this._expandedUuids], + searchQuery: this._searchQuery, + }; + this._container.dispatchEvent( + new CustomEvent(FAVORITES_VIEW_STATE_CHANGED_EVENT, { + detail, + bubbles: true, + composed: true, + }) + ); + } + private _bindEvents(container: HTMLElement): void { this._container = container; @@ -291,6 +358,7 @@ export class ListViewController { this._searchQuery = input.value.toLowerCase(); this._applyFilter(container); + this._dispatchFavoritesViewState(); }; this._graphSettingsHandler = (): void => { @@ -393,5 +461,7 @@ export class ListViewController { row.classList.add("list-row-expanded"); this._ctrl.updateDOM(this._container); } + + this._dispatchFavoritesViewState(); } } diff --git a/src/core/side-panel.ts b/src/core/side-panel.ts index b90446d..15b94a5 100644 --- a/src/core/side-panel.ts +++ b/src/core/side-panel.ts @@ -2,6 +2,7 @@ import { escapeHtml } from "../helpers/sanitize.js"; import { INTEGRATION_DOMAIN, SHEDDING_PRIORITIES, GRAPH_HORIZONS, DEFAULT_GRAPH_HORIZON, ERROR_DISPLAY_MS, INPUT_DEBOUNCE_MS } from "../constants.js"; import { t } from "../i18n.js"; +import { addFavorite, removeFavorite } from "./favorites-store.js"; import type { HomeAssistant, PanelTopology, GraphSettings, CircuitEntities, CircuitGraphOverride, MonitoringPointInfo } from "../types.js"; const PRIORITY_OPTIONS: string[] = Object.keys(SHEDDING_PRIORITIES).filter(k => k !== "unknown" && k !== "always_on"); @@ -17,6 +18,21 @@ interface PanelModeConfig { subDeviceMode?: undefined; topology: PanelTopology; graphSettings: GraphSettings | null; + /** + * When set, the per-target lists in panel mode render a heart button + * beside each horizon selector for toggling favorites. Only the + * dashboard (````) sets this — the standalone card leaves + * it undefined so hearts never appear there. + */ + showFavorites?: boolean; + /** HA device id of the panel whose side panel is open (source of favorites). */ + favoritePanelDeviceId?: string; + /** Circuit uuids already favorited for that panel — drives heart fill. */ + favoriteCircuitUuids?: Set; + /** Sub-device HA device ids already favorited — drives heart fill. */ + favoriteSubDeviceIds?: Set; + /** Override config entry id used for cross-panel service routing (favorites). */ + configEntryId?: string | null; } interface CircuitModeConfig { @@ -33,6 +49,14 @@ interface CircuitModeConfig { monitoringInfo: MonitoringPointInfo | null; showMonitoring?: boolean; graphHorizonInfo: GraphHorizonInfo; + /** Dashboard-only: render the Favorite section on this side panel. */ + showFavorites?: boolean; + /** HA device id of the panel that owns this circuit. */ + favoritePanelDeviceId?: string; + /** Initial favorite state; ``addFavorite``/``removeFavorite`` update live. */ + isFavorite?: boolean; + /** Route domain service calls to this config entry (favorites view). */ + configEntryId?: string | null; } interface SubDeviceModeConfig { @@ -41,7 +65,17 @@ interface SubDeviceModeConfig { subDeviceId: string; name: string; deviceType: string; + /** Sub-device entity registry map from topology, used to pick a routable entity_id for favoriting. */ + entities?: Record; graphHorizonInfo: GraphHorizonInfo; + /** Dashboard-only: render the Favorite section on this side panel. */ + showFavorites?: boolean; + /** HA device id of the panel that owns this sub-device. */ + favoritePanelDeviceId?: string; + /** Initial favorite state. */ + isFavorite?: boolean; + /** Route domain service calls to this config entry (favorites view). */ + configEntryId?: string | null; } type SidePanelConfig = PanelModeConfig | CircuitModeConfig | SubDeviceModeConfig; @@ -232,6 +266,30 @@ const STYLES = ` justify-content: space-between; } + .fav-heart { + background: none; + border: 1px solid var(--divider-color, #e0e0e0); + color: var(--secondary-text-color, #727272); + border-radius: 4px; + padding: 2px 6px; + cursor: pointer; + font-size: 0.9em; + margin-right: 6px; + line-height: 1; + display: inline-flex; + align-items: center; + } + .fav-heart.active { + color: var(--primary-color, #03a9f4); + border-color: var(--primary-color, #03a9f4); + } + .fav-heart:hover:not(.active) { + background: var(--secondary-background-color, #f5f5f5); + } + .fav-heart ha-icon { + --mdc-icon-size: 16px; + } + .panel-mode-info { font-size: 14px; color: var(--primary-text-color, #212121); @@ -251,6 +309,22 @@ const STYLES = ` } `; +/** + * Extract a readable message from a thrown value. Home Assistant WS + * errors are plain ``{code, message}`` objects (not ``Error`` + * instances), so a naive ``String(err)`` would render ``"[object Object]"``. + */ +function _extractErrorMessage(err: unknown): string { + if (err instanceof Error) return err.message; + if (err && typeof err === "object") { + const obj = err as { message?: unknown; error?: unknown; code?: unknown }; + if (typeof obj.message === "string" && obj.message) return obj.message; + if (typeof obj.error === "string" && obj.error) return obj.error; + if (typeof obj.code === "string" && obj.code) return obj.code; + } + return String(err); +} + // ── Component ───────────────────────────────────────────────────────────── class SpanSidePanel extends HTMLElement { @@ -370,7 +444,9 @@ class SpanSidePanel extends HTMLElement { globalSelect.appendChild(opt); } globalSelect.addEventListener("change", () => { - this._callDomainService("set_graph_time_horizon", { horizon: globalSelect.value }) + const data: Record = { horizon: globalSelect.value }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("set_graph_time_horizon", data) .then(() => { this.dispatchEvent(new CustomEvent("graph-settings-changed", { bubbles: true, composed: true })); }) @@ -402,6 +478,11 @@ class SpanSidePanel extends HTMLElement { nameLabel.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;"; row.appendChild(nameLabel); + if (cfg.showFavorites && cfg.favoritePanelDeviceId) { + const heart = this._buildFavoriteHeart(circuit.entities, cfg.favoriteCircuitUuids?.has(uuid) ?? false); + if (heart) row.appendChild(heart); + } + const circuitData = circuitSettings[uuid] || { horizon: globalHorizon, has_override: false }; const effectiveHorizon = circuitData.has_override ? circuitData.horizon : globalHorizon; @@ -418,10 +499,12 @@ class SpanSidePanel extends HTMLElement { } select.addEventListener("change", () => { this._debounce(`circuit-${uuid}`, INPUT_DEBOUNCE_MS, () => { - this._callDomainService("set_circuit_graph_horizon", { + const data: Record = { circuit_id: uuid, horizon: select.value, - }) + }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("set_circuit_graph_horizon", data) .then(() => { this.dispatchEvent(new CustomEvent("graph-settings-changed", { bubbles: true, composed: true })); }) @@ -445,7 +528,9 @@ class SpanSidePanel extends HTMLElement { fontSize: "0.85em", }); resetBtn.addEventListener("click", () => { - this._callDomainService("clear_circuit_graph_horizon", { circuit_id: uuid }) + const data: Record = { circuit_id: uuid }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("clear_circuit_graph_horizon", data) .then(() => { select.value = globalHorizon; resetBtn.remove(); @@ -485,6 +570,11 @@ class SpanSidePanel extends HTMLElement { nameLabel.style.cssText = "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;"; row.appendChild(nameLabel); + if (cfg.showFavorites && cfg.favoritePanelDeviceId) { + const heart = this._buildSubDeviceFavoriteHeart(sub.entities, cfg.favoriteSubDeviceIds?.has(devId) ?? false); + if (heart) row.appendChild(heart); + } + const subDevData = subDeviceSettings[devId] || { horizon: globalHorizon, has_override: false }; const effectiveHorizon = subDevData.has_override ? subDevData.horizon : globalHorizon; @@ -501,10 +591,12 @@ class SpanSidePanel extends HTMLElement { } select.addEventListener("change", () => { this._debounce(`subdev-${devId}`, INPUT_DEBOUNCE_MS, () => { - this._callDomainService("set_subdevice_graph_horizon", { + const data: Record = { subdevice_id: devId, horizon: select.value, - }) + }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("set_subdevice_graph_horizon", data) .then(() => { this.dispatchEvent(new CustomEvent("graph-settings-changed", { bubbles: true, composed: true })); }) @@ -528,7 +620,9 @@ class SpanSidePanel extends HTMLElement { fontSize: "0.85em", }); resetBtn.addEventListener("click", () => { - this._callDomainService("clear_subdevice_graph_horizon", { subdevice_id: devId }) + const data: Record = { subdevice_id: devId }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("clear_subdevice_graph_horizon", data) .then(() => { select.value = globalHorizon; resetBtn.remove(); @@ -564,6 +658,9 @@ class SpanSidePanel extends HTMLElement { body.appendChild(errorEl); this._renderRelaySection(body, cfg); + if (cfg.showFavorites) { + this._renderFavoriteSection(body, cfg); + } this._renderSheddingSection(body, cfg); this._renderGraphHorizonSection(body, cfg); if (cfg.showMonitoring) { @@ -571,6 +668,162 @@ class SpanSidePanel extends HTMLElement { } } + private _favoriteEntityId(entities: CircuitEntities | undefined): string | null { + return entities?.current ?? entities?.power ?? null; + } + + /** + * Pick any entity_id from a sub-device's entity map. The favorites + * service resolves the entity to its parent SPAN panel + sub-device + * id, so any sensor on the sub-device works. Prefers a sensor. + */ + private _subDeviceFavoriteEntityId(entities: Record | undefined): string | null { + if (!entities) return null; + let fallback: string | null = null; + for (const [entityId, info] of Object.entries(entities)) { + if (info.domain === "sensor") return entityId; + if (!fallback) fallback = entityId; + } + return fallback; + } + + /** + * Build a heart toggle for a sub-device row in panel-mode Graph + * Settings. Returns ``null`` when the sub-device has no entities to + * resolve (favorites services need an entity_id). + */ + private _buildSubDeviceFavoriteHeart(entities: Record | undefined, isFavorite: boolean): HTMLButtonElement | null { + const entityId = this._subDeviceFavoriteEntityId(entities); + if (!entityId) return null; + + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = isFavorite ? "fav-heart active" : "fav-heart"; + btn.dataset.role = "fav-heart"; + btn.title = t("sidepanel.save_to_favorites"); + + const icon = document.createElement("ha-icon"); + icon.setAttribute("icon", isFavorite ? "mdi:heart" : "mdi:heart-outline"); + btn.appendChild(icon); + + btn.addEventListener("click", (ev: Event) => { + ev.stopPropagation(); + this._toggleFavoriteEntity(btn, icon, entityId).catch(() => { + // error message shown inside _toggleFavoriteEntity + }); + }); + + return btn; + } + + /** + * Build a heart toggle for a circuit row in panel-mode Graph Settings. + * Returns ``null`` when the circuit has no routable sensor entity + * (favorites services need an entity_id to resolve the target). + */ + private _buildFavoriteHeart(entities: CircuitEntities | undefined, isFavorite: boolean): HTMLButtonElement | null { + const entityId = this._favoriteEntityId(entities); + if (!entityId) return null; + + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = isFavorite ? "fav-heart active" : "fav-heart"; + btn.dataset.role = "fav-heart"; + btn.title = t("sidepanel.save_to_favorites"); + + const icon = document.createElement("ha-icon"); + icon.setAttribute("icon", isFavorite ? "mdi:heart" : "mdi:heart-outline"); + btn.appendChild(icon); + + btn.addEventListener("click", (ev: Event) => { + ev.stopPropagation(); + this._toggleFavoriteEntity(btn, icon, entityId).catch(() => { + // error message shown inside _toggleFavoriteEntity + }); + }); + + return btn; + } + + private async _toggleFavoriteEntity(btn: HTMLButtonElement, icon: HTMLElement, entityId: string): Promise { + if (!this._hass) return; + const wasActive = btn.classList.contains("active"); + const nextActive = !wasActive; + // Optimistically flip; roll back on error. + btn.classList.toggle("active", nextActive); + icon.setAttribute("icon", nextActive ? "mdi:heart" : "mdi:heart-outline"); + try { + if (nextActive) { + await addFavorite(this._hass, entityId); + } else { + await removeFavorite(this._hass, entityId); + } + } catch (err) { + btn.classList.toggle("active", wasActive); + icon.setAttribute("icon", wasActive ? "mdi:heart" : "mdi:heart-outline"); + const message = _extractErrorMessage(err); + this._showError(`${t("sidepanel.favorite_failed")} ${message}`); + throw err; + } + } + + private _renderFavoriteSection(body: HTMLDivElement, cfg: CircuitModeConfig): void { + const entityId = this._favoriteEntityId(cfg.entities); + if (!entityId) return; + + const section = document.createElement("div"); + section.className = "section"; + section.innerHTML = ``; + + const row = document.createElement("div"); + row.className = "field-row"; + + const label = document.createElement("span"); + label.className = "field-label"; + label.textContent = t("sidepanel.save_to_favorites"); + + const toggle = document.createElement("ha-switch") as HaSwitchElement; + toggle.dataset.role = "favorite-toggle"; + if (cfg.isFavorite) toggle.setAttribute("checked", ""); + + toggle.addEventListener("change", () => { + // The authoritative state after a user toggle lives on ``checked``; + // ``hasAttribute("checked")`` still reflects the initial render. + const nextActive = toggle.checked; + this._setFavoriteFromToggle(toggle, entityId, nextActive).catch(() => { + // error already displayed + }); + }); + + row.appendChild(label); + row.appendChild(toggle); + section.appendChild(row); + body.appendChild(section); + } + + private async _setFavoriteFromToggle(toggle: HaSwitchElement, entityId: string, nextActive: boolean): Promise { + if (!this._hass) return; + try { + if (nextActive) { + await addFavorite(this._hass, entityId); + } else { + await removeFavorite(this._hass, entityId); + } + } catch (err) { + // Roll back the switch to its prior state. + if (nextActive) { + toggle.removeAttribute("checked"); + toggle.checked = false; + } else { + toggle.setAttribute("checked", ""); + toggle.checked = true; + } + const message = _extractErrorMessage(err); + this._showError(`${t("sidepanel.favorite_failed")} ${message}`); + throw err; + } + } + private _renderSubDeviceMode(panel: HTMLDivElement, cfg: SubDeviceModeConfig): void { const header = this._createHeader(escapeHtml(cfg.name), escapeHtml(cfg.deviceType)); panel.appendChild(header); @@ -585,9 +838,44 @@ class SpanSidePanel extends HTMLElement { errorEl.style.display = "none"; body.appendChild(errorEl); + if (cfg.showFavorites) { + this._renderSubDeviceFavoriteSection(body, cfg); + } this._renderSubDeviceHorizonSection(body, cfg); } + private _renderSubDeviceFavoriteSection(body: HTMLDivElement, cfg: SubDeviceModeConfig): void { + const entityId = this._subDeviceFavoriteEntityId(cfg.entities); + if (!entityId) return; + + const section = document.createElement("div"); + section.className = "section"; + section.innerHTML = ``; + + const row = document.createElement("div"); + row.className = "field-row"; + + const label = document.createElement("span"); + label.className = "field-label"; + label.textContent = t("sidepanel.save_to_favorites"); + + const toggle = document.createElement("ha-switch") as HaSwitchElement; + toggle.dataset.role = "favorite-toggle"; + if (cfg.isFavorite) toggle.setAttribute("checked", ""); + + toggle.addEventListener("change", () => { + const nextActive = toggle.checked; + this._setFavoriteFromToggle(toggle, entityId, nextActive).catch(() => { + // error already displayed + }); + }); + + row.appendChild(label); + row.appendChild(toggle); + section.appendChild(row); + body.appendChild(section); + } + private _renderSubDeviceHorizonSection(body: HTMLDivElement, cfg: SubDeviceModeConfig): void { const section = document.createElement("div"); section.className = "section"; @@ -808,9 +1096,11 @@ class SpanSidePanel extends HTMLElement { if (btn.classList.contains("active")) return; const circuitId = cfg.uuid; + const baseData: Record = { circuit_id: circuitId }; + if (cfg.configEntryId) baseData.config_entry_id = cfg.configEntryId; if (key === "global") { updateSegmentStates("global"); - this._callDomainService("clear_circuit_graph_horizon", { circuit_id: circuitId }) + this._callDomainService("clear_circuit_graph_horizon", baseData) .then(() => { this.dispatchEvent(new CustomEvent("graph-settings-changed", { bubbles: true, composed: true })); }) @@ -818,7 +1108,7 @@ class SpanSidePanel extends HTMLElement { } else { updateSegmentStates(key); this._callDomainService("set_circuit_graph_horizon", { - circuit_id: circuitId, + ...baseData, horizon: key, }) .then(() => { @@ -899,10 +1189,14 @@ class SpanSidePanel extends HTMLElement { const checked = enableToggle.checked; detailsWrap.style.display = checked ? "block" : "none"; const entityId = cfg.entities?.power || cfg.uuid; - this._callDomainService("set_circuit_threshold", { + const data: Record = { circuit_id: entityId, monitoring_enabled: checked, - }).catch((err: Error) => this._showError(`${t("sidepanel.monitoring_toggle_failed")} ${err.message ?? err}`)); + }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("set_circuit_threshold", data).catch((err: Error) => + this._showError(`${t("sidepanel.monitoring_toggle_failed")} ${err.message ?? err}`) + ); }); // Event: radio change @@ -913,7 +1207,9 @@ class SpanSidePanel extends HTMLElement { thresholdsWrap.style.display = isCustom ? "block" : "none"; if (!isCustom && radio.checked) { const entityId = cfg.entities?.power || cfg.uuid; - this._callDomainService("clear_circuit_threshold", { circuit_id: entityId }).catch((err: Error) => + const data: Record = { circuit_id: entityId }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("clear_circuit_threshold", data).catch((err: Error) => this._showError(`${t("sidepanel.clear_monitoring_failed")} ${err.message ?? err}`) ); } @@ -947,13 +1243,17 @@ class SpanSidePanel extends HTMLElement { const windowM = shadow.querySelector('[data-role="threshold-window-m"]'); const cooldownM = shadow.querySelector('[data-role="threshold-cooldown-m"]'); const entityId = cfg.entities?.power || cfg.uuid; - this._callDomainService("set_circuit_threshold", { + const data: Record = { circuit_id: entityId, continuous_threshold_pct: continuous ? Number(continuous.value) : undefined, spike_threshold_pct: spike ? Number(spike.value) : undefined, window_duration_m: windowM ? Number(windowM.value) : undefined, cooldown_duration_m: cooldownM ? Number(cooldownM.value) : undefined, - }).catch((err: Error) => this._showError(`${t("sidepanel.save_threshold_failed")} ${err.message ?? err}`)); + }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("set_circuit_threshold", data).catch((err: Error) => + this._showError(`${t("sidepanel.save_threshold_failed")} ${err.message ?? err}`) + ); }); }); @@ -1005,12 +1305,16 @@ class SpanSidePanel extends HTMLElement { const continuous = shadow.querySelector('[data-role="threshold-continuous"]'); const spike = shadow.querySelector('[data-role="threshold-spike"]'); const windowM = shadow.querySelector('[data-role="threshold-window-m"]'); - this._callDomainService("set_circuit_threshold", { + const data: Record = { circuit_id: cfg.uuid, continuous_threshold_pct: continuous ? Number(continuous.value) : undefined, spike_threshold_pct: spike ? Number(spike.value) : undefined, window_duration_m: windowM ? Number(windowM.value) : undefined, - }).catch((err: Error) => this._showError(`${t("sidepanel.save_threshold_failed")} ${err.message ?? err}`)); + }; + if (cfg.configEntryId) data.config_entry_id = cfg.configEntryId; + this._callDomainService("set_circuit_threshold", data).catch((err: Error) => + this._showError(`${t("sidepanel.save_threshold_failed")} ${err.message ?? err}`) + ); }); }); } diff --git a/src/i18n.ts b/src/i18n.ts index cfe9673..be60364 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -147,6 +147,14 @@ const translations: Record> = { "sidepanel.monitoring_toggle_failed": "Monitoring toggle failed:", "sidepanel.clear_monitoring_failed": "Clear monitoring failed:", "sidepanel.save_threshold_failed": "Save threshold failed:", + "sidepanel.favorite": "Favorite", + "sidepanel.save_to_favorites": "Save to favorites", + "sidepanel.favorite_failed": "Favorite update failed:", + + // Favorites pseudo-panel + "panel.favorites": "Favorites", + "panel.favorites_summary_one": "1 circuit across {panels} panels", + "panel.favorites_summary_many": "{circuits} circuits across {panels} panels", // Monitoring status bar "status.monitoring": "Monitoring", @@ -314,6 +322,12 @@ const translations: Record> = { "sidepanel.monitoring_toggle_failed": "Error al cambiar monitoreo:", "sidepanel.clear_monitoring_failed": "Error al limpiar monitoreo:", "sidepanel.save_threshold_failed": "Error al guardar umbral:", + "sidepanel.favorite": "Favorito", + "sidepanel.save_to_favorites": "Guardar en favoritos", + "sidepanel.favorite_failed": "Error al actualizar favoritos:", + "panel.favorites": "Favoritos", + "panel.favorites_summary_one": "1 circuito en {panels} paneles", + "panel.favorites_summary_many": "{circuits} circuitos en {panels} paneles", "status.monitoring": "Monitoreo", "status.circuits": "circuitos", "status.mains": "alimentaci\u00f3n", @@ -473,6 +487,12 @@ const translations: Record> = { "sidepanel.monitoring_toggle_failed": "\u00c9chec du basculement de surveillance :", "sidepanel.clear_monitoring_failed": "\u00c9chec de l'effacement de surveillance :", "sidepanel.save_threshold_failed": "\u00c9chec de la sauvegarde du seuil :", + "sidepanel.favorite": "Favori", + "sidepanel.save_to_favorites": "Enregistrer dans les favoris", + "sidepanel.favorite_failed": "\u00c9chec de la mise \u00e0 jour du favori :", + "panel.favorites": "Favoris", + "panel.favorites_summary_one": "1 circuit sur {panels} panneaux", + "panel.favorites_summary_many": "{circuits} circuits sur {panels} panneaux", "status.monitoring": "Surveillance", "status.circuits": "circuits", "status.mains": "alimentation", @@ -634,6 +654,12 @@ const translations: Record> = { "sidepanel.monitoring_toggle_failed": "\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u5207\u308a\u66ff\u3048\u5931\u6557:", "sidepanel.clear_monitoring_failed": "\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u30af\u30ea\u30a2\u5931\u6557:", "sidepanel.save_threshold_failed": "\u3057\u304d\u3044\u5024\u4fdd\u5b58\u5931\u6557:", + "sidepanel.favorite": "\u304a\u6c17\u306b\u5165\u308a", + "sidepanel.save_to_favorites": "\u304a\u6c17\u306b\u5165\u308a\u306b\u4fdd\u5b58", + "sidepanel.favorite_failed": "\u304a\u6c17\u306b\u5165\u308a\u306e\u66f4\u65b0\u306b\u5931\u6557:", + "panel.favorites": "\u304a\u6c17\u306b\u5165\u308a", + "panel.favorites_summary_one": "{panels} \u30d1\u30cd\u30eb\u306b\u308f\u305f\u308b 1 \u56de\u8def", + "panel.favorites_summary_many": "{panels} \u30d1\u30cd\u30eb\u306b\u308f\u305f\u308b {circuits} \u56de\u8def", "status.monitoring": "\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0", "status.circuits": "\u56de\u8def", "status.mains": "\u4e3b\u96fb\u6e90", @@ -797,6 +823,12 @@ const translations: Record> = { "sidepanel.monitoring_toggle_failed": "Falha ao alternar monitoramento:", "sidepanel.clear_monitoring_failed": "Falha ao limpar monitoramento:", "sidepanel.save_threshold_failed": "Falha ao salvar limite:", + "sidepanel.favorite": "Favorito", + "sidepanel.save_to_favorites": "Salvar nos favoritos", + "sidepanel.favorite_failed": "Falha ao atualizar favorito:", + "panel.favorites": "Favoritos", + "panel.favorites_summary_one": "1 circuito em {panels} painéis", + "panel.favorites_summary_many": "{circuits} circuitos em {panels} painéis", "status.monitoring": "Monitoramento", "status.circuits": "circuitos", "status.mains": "alimenta\u00e7\u00e3o", diff --git a/src/panel/span-panel.ts b/src/panel/span-panel.ts index bb9bb17..f6457df 100644 --- a/src/panel/span-panel.ts +++ b/src/panel/span-panel.ts @@ -6,17 +6,66 @@ import { setLanguage, t } from "../i18n.js"; import "../core/side-panel.js"; import { DashboardTab } from "./tab-dashboard.js"; import { MonitoringTab } from "./tab-monitoring.js"; -import { ListViewController } from "../core/list-view-controller.js"; +import { ListViewController, type FavoritesViewStateDetail } from "../core/list-view-controller.js"; import { DashboardController } from "../core/dashboard-controller.js"; import { buildTabBarHTML } from "../core/tab-bar-renderer.js"; import { subscribeAreaUpdates } from "../core/area-resolver.js"; import { discoverTopology } from "../card/card-discovery.js"; +import { buildHeaderHTML } from "../core/header-renderer.js"; +import { buildSubDevicesHTML } from "../core/sub-device-renderer.js"; +import { escapeHtml } from "../helpers/sanitize.js"; import { CARD_STYLES } from "../card/card-styles.js"; -import type { HomeAssistant, PanelDevice, CardConfig } from "../types.js"; +import { FAVORITES_CHANGED_EVENT, FavoritesCache, countFavorites, hasAnyFavorites } from "../core/favorites-store.js"; +import { FavoritesController } from "../core/favorites-controller.js"; +import type { CardConfig, FavoritesMap, FavoritesTopology, HomeAssistant, PanelDevice, PanelTopology } from "../types.js"; -interface HaMenuButton extends HTMLElement { - hass: HomeAssistant; - narrow: boolean; +const FAVORITES_PANEL_ID = "favorites"; +const FAVORITES_VIEW_STATE_KEY = "span_panel_favorites_view_state"; + +interface FavoritesViewState { + activeTab?: "activity" | "area" | "monitoring"; + expanded: { activity: string[]; area: string[] }; + searchQuery?: string; +} + +function _defaultFavoritesViewState(): FavoritesViewState { + return { expanded: { activity: [], area: [] } }; +} + +function _loadFavoritesViewState(): FavoritesViewState { + try { + const raw = localStorage.getItem(FAVORITES_VIEW_STATE_KEY); + if (!raw) return _defaultFavoritesViewState(); + const parsed = JSON.parse(raw) as Partial | null; + if (!parsed || typeof parsed !== "object") return _defaultFavoritesViewState(); + const expanded = parsed.expanded ?? { activity: [], area: [] }; + return { + activeTab: parsed.activeTab, + expanded: { + activity: Array.isArray(expanded.activity) ? expanded.activity : [], + area: Array.isArray(expanded.area) ? expanded.area : [], + }, + searchQuery: typeof parsed.searchQuery === "string" ? parsed.searchQuery : undefined, + }; + } catch { + return _defaultFavoritesViewState(); + } +} + +function _saveFavoritesViewState(viewState: FavoritesViewState): void { + try { + localStorage.setItem(FAVORITES_VIEW_STATE_KEY, JSON.stringify(viewState)); + } catch { + // LocalStorage quota or disabled — non-fatal; state doesn't persist. + } +} + +function _clearFavoritesViewState(): void { + try { + localStorage.removeItem(FAVORITES_VIEW_STATE_KEY); + } catch { + // non-fatal + } } type TabName = "dashboard" | "activity" | "area" | "monitoring"; @@ -35,13 +84,24 @@ export class SpanPanelElement extends LitElement { @state() private _discovered = false; @state() private _discoveryError: string | null = null; @state() private _chartMetric: string | undefined; + @state() private _favorites: FavoritesMap = {}; + + private _favoritesViewState: FavoritesViewState = _defaultFavoritesViewState(); private _dashboardTab = new DashboardTab(); private _monitoringTab = new MonitoringTab(); private _listDashCtrl = new DashboardController(); private _listCtrl = new ListViewController(this._listDashCtrl); + private _favCache = new FavoritesCache(); + private _favCtrl = new FavoritesController(); + /** + * Per-panel monitoring tabs used when rendering the Favorites view's + * Monitoring tab — one block per contributing panel's config entry. + */ + private _favoritesMonitoringTabs: Map = new Map(); private _areaUnsub: (() => void) | null = null; private _onVisibilityChange: (() => void) | null = null; + private _onFavoritesChanged: (() => void) | null = null; private _deviceRegistryUnsub: Promise<() => void> | null = null; static styles = css` @@ -145,6 +205,11 @@ export class SpanPanelElement extends LitElement { }; document.addEventListener("visibilitychange", this._onVisibilityChange); + this._onFavoritesChanged = (): void => { + this._refreshFavorites(); + }; + document.addEventListener(FAVORITES_CHANGED_EVENT, this._onFavoritesChanged); + this._subscribeDeviceRegistry(); } @@ -153,6 +218,8 @@ export class SpanPanelElement extends LitElement { this._monitoringTab.stop(); this._listCtrl.stop(); this._listDashCtrl.stopIntervals(); + for (const tab of this._favoritesMonitoringTabs.values()) tab.stop(); + this._favoritesMonitoringTabs.clear(); if (this._areaUnsub) { this._areaUnsub(); this._areaUnsub = null; @@ -161,6 +228,10 @@ export class SpanPanelElement extends LitElement { document.removeEventListener("visibilitychange", this._onVisibilityChange); this._onVisibilityChange = null; } + if (this._onFavoritesChanged) { + document.removeEventListener(FAVORITES_CHANGED_EVENT, this._onFavoritesChanged); + this._onFavoritesChanged = null; + } this._unsubscribeDeviceRegistry(); super.disconnectedCallback(); } @@ -177,13 +248,6 @@ export class SpanPanelElement extends LitElement { this._dashboardTab.hass = this.hass; this._listDashCtrl.hass = this.hass; - // Wire up ha-menu-button with current hass/narrow - const menuBtn = this.renderRoot.querySelector("ha-menu-button"); - if (menuBtn) { - menuBtn.hass = this.hass; - menuBtn.narrow = this.narrow; - } - if (!this._discovered) { this._discoverPanels(); } else if (!this.shadowRoot!.getElementById("tab-content")) { @@ -196,11 +260,6 @@ export class SpanPanelElement extends LitElement { } } - if (changedProps.has("narrow")) { - const menuBtn = this.renderRoot.querySelector("ha-menu-button"); - if (menuBtn) menuBtn.narrow = this.narrow; - } - // Render tab content when discovery completes or active tab/panel/metric changes if ( this._discovered && @@ -209,6 +268,18 @@ export class SpanPanelElement extends LitElement { this._scheduleTabRender(); } + // Keep the @@ -255,20 +343,7 @@ export class SpanPanelElement extends LitElement {
-
- ${unsafeHTML( - buildTabBarHTML( - [ - { id: "dashboard", label: t("tab.by_panel"), icon: "mdi:view-dashboard" }, - { id: "activity", label: t("tab.by_activity"), icon: "mdi:sort-descending" }, - { id: "area", label: t("tab.by_area"), icon: "mdi:home-group" }, - { id: "monitoring", label: t("tab.monitoring"), icon: "mdi:monitor-eye" }, - ], - this._activeTab, - "text" - ) - )} -
+
${unsafeHTML(buildTabBarHTML(this._buildTabList(), this._activeTab, "text"))}
@@ -281,6 +356,7 @@ export class SpanPanelElement extends LitElement { @side-panel-closed=${this._onSidePanelClosed} @graph-settings-changed=${this._onGraphSettingsChanged} @navigate-tab=${this._onNavigateTab} + @favorites-view-state-changed=${this._onFavoritesViewStateChangedEvent} >
@@ -293,6 +369,11 @@ export class SpanPanelElement extends LitElement { const select = e.target as HTMLSelectElement; this._selectedPanelId = select.value; localStorage.setItem("span_panel_selected", select.value); + // The Favorites pseudo-panel has no "By Panel" tab, so re-route away + // from it when the user lands on favorites with that tab active. + if (this._isFavoritesView && this._activeTab === "dashboard") { + this._activeTab = "activity"; + } if (this._areaUnsub) { this._areaUnsub(); this._areaUnsub = null; @@ -300,6 +381,10 @@ export class SpanPanelElement extends LitElement { this._scheduleTabRender(); } + private get _isFavoritesView(): boolean { + return this._selectedPanelId === FAVORITES_PANEL_ID; + } + private _onTabClick(e: Event): void { const target = e.target as HTMLElement; const btn = target.closest(".shared-tab"); @@ -307,6 +392,10 @@ export class SpanPanelElement extends LitElement { const tab = btn.dataset.tab as TabName | undefined; if (!tab || tab === this._activeTab) return; this._activeTab = tab; + if (this._isFavoritesView && tab !== "dashboard") { + this._favoritesViewState.activeTab = tab; + _saveFavoritesViewState(this._favoritesViewState); + } this._scheduleTabRender(); } @@ -363,6 +452,19 @@ export class SpanPanelElement extends LitElement { this._scheduleTabRender(); } + private _onFavoritesViewStateChangedEvent(ev: Event): void { + if (!this._isFavoritesView) return; + const detail = (ev as CustomEvent).detail; + if (!detail) return; + const viewState = this._favoritesViewState; + viewState.activeTab = detail.view; + // Prune expansion ids to those still present in the merged topology. + const valid = this._listDashCtrl.topology?.circuits ?? {}; + viewState.expanded[detail.view] = detail.expanded.filter(id => id in valid); + viewState.searchQuery = detail.searchQuery; + _saveFavoritesViewState(viewState); + } + // ── Internal helpers ──────────────────────────────────────────────── private _subscribeDeviceRegistry(): void { @@ -383,46 +485,178 @@ export class SpanPanelElement extends LitElement { const devices = await this.hass.callWS({ type: "config/device_registry/list", }); - const panels = devices.filter((d: PanelDevice) => d.identifiers?.some(id => id[0] === INTEGRATION_DOMAIN) && !d.via_device_id); + const realPanels = devices.filter((d: PanelDevice) => d.identifiers?.some(id => id[0] === INTEGRATION_DOMAIN) && !d.via_device_id); - const currentIds = new Set(this._panels.map(p => p.id)); - const newIds = new Set(panels.map(p => p.id)); - if (currentIds.size === newIds.size && [...currentIds].every(id => newIds.has(id))) return; + const prevRealIds = new Set(this._panels.filter(p => p.id !== FAVORITES_PANEL_ID).map(p => p.id)); + const newRealIds = new Set(realPanels.map(p => p.id)); + const realChanged = prevRealIds.size !== newRealIds.size || [...prevRealIds].some(id => !newRealIds.has(id)); + if (!realChanged) return; - this._panels = panels; + this._panels = this._buildPanelList(realPanels, this._favorites); if (!this._panels.some(p => p.id === this._selectedPanelId) && this._panels.length > 0) { - this._selectedPanelId = this._panels[0]!.id; - localStorage.setItem("span_panel_selected", this._selectedPanelId); + const firstReal = realPanels[0]; + if (firstReal) { + this._selectedPanelId = firstReal.id; + localStorage.setItem("span_panel_selected", this._selectedPanelId); + } } } private async _discoverPanels(): Promise { if (!this.hass) return; + let realPanels: PanelDevice[]; try { const devices = await this.hass.callWS({ type: "config/device_registry/list", }); - this._panels = devices.filter((d: PanelDevice) => d.identifiers?.some(id => id[0] === INTEGRATION_DOMAIN) && !d.via_device_id); + realPanels = devices.filter((d: PanelDevice) => d.identifiers?.some(id => id[0] === INTEGRATION_DOMAIN) && !d.via_device_id); } catch (err) { console.error("SPAN Panel: device discovery failed", err); this._discoveryError = `Discovery failed: ${(err as Error).message ?? err}`; return; } + this._favorites = await this._loadFavorites(); + this._panels = this._buildPanelList(realPanels, this._favorites); + this._favoritesViewState = _loadFavoritesViewState(); + this._discoveryError = null; this._discovered = true; const stored = localStorage.getItem("span_panel_selected"); if (stored && this._panels.some(p => p.id === stored)) { this._selectedPanelId = stored; - } else if (this._panels.length > 0) { - this._selectedPanelId = this._panels[0]!.id; + } else if (realPanels.length > 0) { + this._selectedPanelId = realPanels[0]!.id; + } + + // Restore the user's favorites tab when re-entering the pseudo-panel. + if (this._selectedPanelId === FAVORITES_PANEL_ID) { + const restoredTab = this._favoritesViewState.activeTab; + if (restoredTab === "activity" || restoredTab === "area" || restoredTab === "monitoring") { + this._activeTab = restoredTab; + } else if (this._activeTab === "dashboard") { + this._activeTab = "activity"; + } } this._chartMetric = localStorage.getItem("span_panel_metric") || "power"; } + /** + * Build the dropdown list, optionally prepending a synthetic Favorites + * entry when at least one favorite is configured. + */ + private _buildPanelList(realPanels: PanelDevice[], favorites: FavoritesMap): PanelDevice[] { + if (!hasAnyFavorites(favorites)) return realPanels; + const favoritesEntry: PanelDevice = { + id: FAVORITES_PANEL_ID, + name: t("panel.favorites"), + model: "__favorites__", + }; + return [favoritesEntry, ...realPanels]; + } + + private async _loadFavorites(): Promise { + if (!this.hass) return {}; + try { + return await this._favCache.fetch(this.hass); + } catch (err) { + console.warn("SPAN Panel: favorites fetch failed", err); + return {}; + } + } + + /** + * React to a ``favorites-changed`` event dispatched by the side panel. + * Re-fetches the favorites map and updates the dropdown entry + the + * per-panel favorites passed into controllers. Does NOT tear down the + * tab content — that would close any open side panel. The next panel + * or tab switch naturally picks up the new list for the Favorites view. + */ + private async _refreshFavorites(): Promise { + this._favCache.invalidate(); + const favorites = await this._loadFavorites(); + const wasOnFavorites = this._selectedPanelId === FAVORITES_PANEL_ID; + this._favorites = favorites; + + const realPanels = this._panels.filter(p => p.id !== FAVORITES_PANEL_ID); + this._panels = this._buildPanelList(realPanels, favorites); + + if (wasOnFavorites && !hasAnyFavorites(favorites)) { + // Last favorite removed — fall back to the first real panel and + // drop the persisted Favorites view state so a fresh return opens + // with defaults. The selectedPanelId change reactively re-renders + // the tab content via ``updated()``. + _clearFavoritesViewState(); + this._favoritesViewState = _defaultFavoritesViewState(); + const fallback = realPanels[0]; + if (fallback) { + this._selectedPanelId = fallback.id; + localStorage.setItem("span_panel_selected", fallback.id); + } else { + this._selectedPanelId = null; + } + } else if (!this._isFavoritesView) { + // Keep per-panel favorites fresh so the next gear click (or a + // re-opened side panel) reflects the current heart state. + this._applyPanelFavorites(); + } + } + + /** + * Build the tab list for the current panel selection. The Favorites + * pseudo-panel drops "By Panel" because its merged topology has no + * physical breaker grid to render. + */ + private _buildTabList(): { id: string; label: string; icon: string }[] { + const tabs: { id: string; label: string; icon: string }[] = []; + if (!this._isFavoritesView) { + tabs.push({ id: "dashboard", label: t("tab.by_panel"), icon: "mdi:view-dashboard" }); + } + tabs.push( + { id: "activity", label: t("tab.by_activity"), icon: "mdi:sort-descending" }, + { id: "area", label: t("tab.by_area"), icon: "mdi:home-group" }, + { id: "monitoring", label: t("tab.monitoring"), icon: "mdi:monitor-eye" } + ); + return tabs; + } + + /** + * Build the persistent panel-stats header HTML for the current real + * panel. Omits the "Enable Switches" slide-to-confirm in list/monitoring + * views where breaker toggles aren't rendered anyway. + */ + private _buildCurrentPanelHeaderHTML(topology: PanelTopology, config: CardConfig): string { + return buildHeaderHTML(topology, config, { showSwitches: false }); + } + + /** + * Build a minimal summary strip for the Favorites pseudo-panel. The + * aggregate has no panel-level stats to render, so we surface the + * circuit + panel counts and the W/A unit toggle (since the list view + * no longer renders its own — the persistent header owns it). + */ + private _buildFavoritesSummaryHTML(): string { + const panelCount = Object.values(this._favorites).filter(e => (e.circuits?.length ?? 0) > 0 || (e.sub_devices?.length ?? 0) > 0).length; + const circuitCount = countFavorites(this._favorites); + const key = circuitCount === 1 ? "panel.favorites_summary_one" : "panel.favorites_summary_many"; + const template = t(key); + const summary = template.replace("{circuits}", String(circuitCount)).replace("{panels}", String(panelCount)); + const isAmpsMode = (this._chartMetric || "power") === "current"; + return ` +
+
${escapeHtml(t("panel.favorites"))}
+
${escapeHtml(summary)}
+
+ + +
+
+ `; + } + private _buildDashboardConfig(): CardConfig { return { chart_metric: this._chartMetric, @@ -443,10 +677,21 @@ export class SpanPanelElement extends LitElement { this._monitoringTab.stop(); this._listCtrl.stop(); this._listDashCtrl.stopIntervals(); + for (const tab of this._favoritesMonitoringTabs.values()) tab.stop(); + this._favoritesMonitoringTabs.clear(); const container = this.shadowRoot!.getElementById("tab-content"); if (!container) return; + if (this._isFavoritesView) { + await this._renderFavoritesTab(container); + return; + } + + this._listDashCtrl.clearFavoriteRefs(); + this._listCtrl.setViewName(null); + this._applyPanelFavorites(); + switch (this._activeTab) { case "dashboard": { container.innerHTML = ""; @@ -466,7 +711,8 @@ export class SpanPanelElement extends LitElement { this._listDashCtrl.init(result.topology, config, this.hass, entryId); await this._listDashCtrl.monitoringCache.fetch(this.hass, entryId); await this._listDashCtrl.fetchAndBuildHorizonMaps(); - this._listCtrl.renderActivityView(container, this.hass, result.topology!, config, this._listDashCtrl.monitoringCache.status); + const headerHTML = result.topology ? this._buildCurrentPanelHeaderHTML(result.topology, config) : ""; + this._listCtrl.renderActivityView(container, this.hass, result.topology!, config, this._listDashCtrl.monitoringCache.status, headerHTML); container.insertAdjacentHTML("afterbegin", ``); await this._listDashCtrl.loadHistory(); this._listDashCtrl.updateDOM(container); @@ -489,7 +735,8 @@ export class SpanPanelElement extends LitElement { this._listDashCtrl.init(result.topology, config, this.hass, areaEntryId); await this._listDashCtrl.monitoringCache.fetch(this.hass, areaEntryId); await this._listDashCtrl.fetchAndBuildHorizonMaps(); - this._listCtrl.renderAreaView(container, this.hass, result.topology!, config, this._listDashCtrl.monitoringCache.status); + const headerHTML = result.topology ? this._buildCurrentPanelHeaderHTML(result.topology, config) : ""; + this._listCtrl.renderAreaView(container, this.hass, result.topology!, config, this._listDashCtrl.monitoringCache.status, headerHTML); container.insertAdjacentHTML("afterbegin", ``); await this._listDashCtrl.loadHistory(); this._listDashCtrl.updateDOM(container); @@ -518,9 +765,142 @@ export class SpanPanelElement extends LitElement { container.innerHTML = ""; const monDevice = this._panels.find(p => p.id === this._selectedPanelId); const monEntryId = monDevice?.config_entries?.[0] ?? null; + // Monitoring is a pure configuration view — no panel-stats header. await this._monitoringTab.render(container, this.hass, monEntryId ?? undefined); break; } } } + + /** + * Render the Favorites pseudo-panel for the current active tab. + * Skips the "By Panel" tab entirely — that tab is filtered out of the + * tab bar and ``_onPanelChange`` auto-reroutes to Activity when the + * user switches panels while it was active. + */ + private async _renderFavoritesTab(container: HTMLElement): Promise { + if (this._activeTab === "dashboard") this._activeTab = "activity"; + + container.innerHTML = ""; + if (!this.hass) return; + + const realPanels = this._panels.filter(p => p.id !== FAVORITES_PANEL_ID); + const build = await this._favCtrl.build(this.hass, this._favorites, realPanels); + const merged = build.topology; + const primaryEntryId = build.entryIds[0] ?? null; + + const hasCircuits = Object.keys(merged.circuits).length > 0; + const hasSubDevices = Object.keys(merged.sub_devices ?? {}).length > 0; + if (!hasCircuits && !hasSubDevices) { + const empty = document.createElement("p"); + empty.style.color = "var(--secondary-text-color)"; + empty.style.padding = "24px"; + empty.textContent = t("list.no_results"); + container.appendChild(empty); + return; + } + + this._listDashCtrl.setFavoriteRefs(merged._favoriteRefs); + this._listDashCtrl.setPanelFavorites(null); + + if (this._activeTab === "monitoring") { + this._listCtrl.setViewName(null); + await this._renderFavoritesMonitoring(container, build.entryIds, realPanels); + return; + } + + const viewName = this._activeTab as "activity" | "area"; + const validCircuitIds = new Set(Object.keys(merged.circuits)); + const storedExpanded = this._favoritesViewState.expanded[viewName].filter(id => validCircuitIds.has(id)); + this._listCtrl.setViewName(viewName); + this._listCtrl.setInitialExpansion(storedExpanded); + this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery ?? ""); + + const config = this._buildDashboardConfig(); + this._listDashCtrl.init(merged, config, this.hass, primaryEntryId); + await this._listDashCtrl.fetchAndBuildHorizonMaps(); + + const summaryHTML = this._buildFavoritesSummaryHTML(); + const subDevicesHTML = hasSubDevices + ? `
+
${buildSubDevicesHTML(merged, this.hass, config)}
+
` + : ""; + const headerHTML = summaryHTML + subDevicesHTML; + try { + if (viewName === "activity") { + this._listCtrl.renderActivityView(container, this.hass, merged as FavoritesTopology, config, null, headerHTML); + } else { + this._listCtrl.renderAreaView(container, this.hass, merged as FavoritesTopology, config, null, headerHTML); + } + container.insertAdjacentHTML("afterbegin", ``); + await this._listDashCtrl.loadHistory(); + this._listDashCtrl.updateDOM(container); + this._listDashCtrl.startIntervals(container); + } catch (err) { + const errEl = document.createElement("p"); + errEl.style.color = "var(--error-color)"; + errEl.textContent = (err as Error).message; + container.appendChild(errEl); + } + } + + private async _renderFavoritesMonitoring(container: HTMLElement, entryIds: string[], realPanels: PanelDevice[]): Promise { + if (!this.hass) return; + + container.insertAdjacentHTML("beforeend", this._buildFavoritesSummaryHTML()); + + const wrapper = document.createElement("div"); + wrapper.className = "favorites-monitoring-stack"; + container.appendChild(wrapper); + + const panelsByEntry = new Map(); + for (const panel of realPanels) { + const eid = panel.config_entries?.[0]; + if (eid) panelsByEntry.set(eid, panel); + } + + for (const entryId of entryIds) { + const panel = panelsByEntry.get(entryId); + const block = document.createElement("div"); + block.className = "favorites-monitoring-block"; + block.style.marginBottom = "24px"; + + const heading = document.createElement("h3"); + heading.style.margin = "8px 0 12px"; + heading.style.fontSize = "1em"; + heading.textContent = panel?.name_by_user ?? panel?.name ?? entryId; + block.appendChild(heading); + + const body = document.createElement("div"); + block.appendChild(body); + wrapper.appendChild(block); + + const tab = new MonitoringTab(); + this._favoritesMonitoringTabs.set(entryId, tab); + await tab.render(body, this.hass, entryId); + } + } + + /** + * For real-panel renders, push the current panel's favorited circuit + * uuids and sub-device ids into the shared list controller so hearts + * render with the right fill state when a side panel opens from any + * gear click on the dashboard. + */ + private _applyPanelFavorites(): void { + if (!this._selectedPanelId || this._isFavoritesView) { + this._listDashCtrl.setPanelFavorites(null); + this._dashboardTab.setPanelFavorites(null); + return; + } + const entry = this._favorites[this._selectedPanelId]; + const info = { + panelDeviceId: this._selectedPanelId, + circuitUuids: new Set(entry?.circuits ?? []), + subDeviceIds: new Set(entry?.sub_devices ?? []), + }; + this._listDashCtrl.setPanelFavorites(info); + this._dashboardTab.setPanelFavorites(info); + } } diff --git a/src/panel/tab-dashboard.ts b/src/panel/tab-dashboard.ts index 5da50f2..5bad7ee 100644 --- a/src/panel/tab-dashboard.ts +++ b/src/panel/tab-dashboard.ts @@ -9,6 +9,12 @@ import { CARD_STYLES } from "../card/card-styles.js"; import "../core/side-panel.js"; import type { HomeAssistant, CardConfig } from "../types.js"; +export interface PanelFavoriteInfo { + panelDeviceId: string; + circuitUuids: Set; + subDeviceIds: Set; +} + export class DashboardTab { private readonly _ctrl = new DashboardController(); private _container: HTMLElement | null = null; @@ -25,6 +31,15 @@ export class DashboardTab { this._ctrl.hass = val; } + /** + * Provide the current panel's favorites (for heart toggles in the + * Graph Settings / circuit side panels). Pass ``null`` to hide hearts + * when the dashboard is not the active rendering context. + */ + setPanelFavorites(info: PanelFavoriteInfo | null): void { + this._ctrl.setPanelFavorites(info); + } + async render(container: HTMLElement, hass: HomeAssistant, deviceId: string, config: CardConfig, configEntryId?: string | null): Promise { this.stop(); this._ctrl.reset(); diff --git a/src/panel/tab-monitoring.ts b/src/panel/tab-monitoring.ts index 831fe29..817217d 100644 --- a/src/panel/tab-monitoring.ts +++ b/src/panel/tab-monitoring.ts @@ -45,11 +45,13 @@ export class MonitoringTab { private _debounceTimer: ReturnType | null; private _configEntryId: string | null; private _notifyCloseHandler: ((e: MouseEvent) => void) | null; + private _headerHTML: string; constructor() { this._debounceTimer = null; this._configEntryId = null; this._notifyCloseHandler = null; + this._headerHTML = ""; } stop(): void { @@ -63,8 +65,9 @@ export class MonitoringTab { } } - async render(container: HTMLElement, hass: HomeAssistant, configEntryId?: string): Promise { + async render(container: HTMLElement, hass: HomeAssistant, configEntryId?: string, headerHTML: string = ""): Promise { if (configEntryId !== undefined) this._configEntryId = configEntryId; + this._headerHTML = headerHTML; if (this._notifyCloseHandler) { document.removeEventListener("click", this._notifyCloseHandler as EventListener); this._notifyCloseHandler = null; @@ -191,6 +194,7 @@ export class MonitoringTab { .join(""); container.innerHTML = ` + ${this._headerHTML}

${t("monitoring.heading")}

diff --git a/src/types.ts b/src/types.ts index c2ff5cf..5f22b48 100644 --- a/src/types.ts +++ b/src/types.ts @@ -125,6 +125,48 @@ export interface ChartMetricDef { fixedMax?: number; } +// -- Favorites -- + +export interface PanelFavoritesEntry { + circuits: string[]; + sub_devices: string[]; +} + +/** + * Cross-panel favorites, keyed by the main SPAN panel device id + * (HA device registry id) and grouping the panel-local circuit uuids + * and sub-device HA device ids the user has marked. + */ +export interface FavoritesMap { + [panelDeviceId: string]: PanelFavoritesEntry; +} + +export type FavoriteKind = "circuit" | "sub_device"; + +/** + * Origin metadata for a favorited circuit or sub-device, used by the + * Favorites pseudo-panel to route per-target service calls back to the + * correct SPAN panel/config entry after aggregating across panels. + */ +export interface FavoriteRef { + panelDeviceId: string; + kind: FavoriteKind; + /** Real circuit uuid (kind ``circuit``) or HA device id (kind ``sub_device``). */ + targetId: string; + configEntryId: string | null; +} + +/** + * Merged topology for the Favorites pseudo-panel. Circuits and + * sub-devices are keyed by composite ids ``"{panelDeviceId}|{targetId}"`` + * so identifiers from different panels can't collide. + * ``_favoriteRefs`` maps composite ids back to their origin for + * downstream service calls. + */ +export interface FavoritesTopology extends PanelTopology { + _favoriteRefs: Record; +} + // -- Graph settings -- export interface CircuitGraphOverride { From 46b56ae24d736f61d198f5c513f8cadd9d73f6a6 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:45:54 -0700 Subject: [PATCH 02/97] fix: thread config_entry_id from sub-device side panel horizon The sub-device-mode side panel's horizon segment buttons (BESS, EVSE) called set_subdevice_graph_horizon / clear_subdevice_graph_horizon without config_entry_id, so the backend's _get_horizon_manager fell back to the FIRST loaded SPAN entry's manager. On multi-panel installs the override was written to the wrong panel's manager and the chart stayed at the global default. Panel-mode (Graph Settings list) and the circuit-mode side panel already threaded it; the sub-device side panel now does too, sourced from cfg.configEntryId set by DashboardController. Also documents the 0.9.3 release in CHANGELOG. --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ dist/span-panel-card.js | 2 +- dist/span-panel.js | 2 +- src/core/side-panel.ts | 13 ++++++++----- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5912a4d..df2843d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## 0.9.3 + +### Added + +- **Cross-panel Favorites view** — A synthetic "Favorites" entry appears in the dashboard panel dropdown (only when at least one favorite is configured) and + aggregates favorited circuits and sub-devices (BESS, EVSE) from every configured SPAN panel into a single workspace. + - Heart toggles in the Graph Settings side panel and per-circuit / per-sub-device side panels (dashboard mode only — never in the standalone Lovelace card). + - Favorites view shows By Activity / By Area / Monitoring tabs (no By Panel). When more than one panel contributes, circuit and sub-device names are prefixed + with their panel name. Sub-device tiles render above the circuit list. Monitoring stacks per-panel blocks. + - Stateful: active tab, expanded rows, and search query persist via localStorage and restore on return. +- **Persistent panel-stats header** — Site / Grid / Upstream / Downstream / Solar / Battery stats now stay visible across all tabs (By Panel, By Activity, By + Area, Monitoring) on real panels. Lifted out of the By-Panel grid into the wrapper. Favorites pseudo-panel shows a count summary instead. + +### Fixed + +- **Sub-device per-target horizon override** — Setting an individual BESS or EVSE horizon from the sub-device side panel had no effect when more than one SPAN + panel was configured: the service call omitted `config_entry_id`, so the backend wrote the override to the first loaded entry's manager (wrong panel). The + per-circuit side panel and the panel-mode (Graph Settings) list already threaded it; the sub-device side panel now does too. +- **`` first-render crash** — The dashboard panel no longer creates `ha-menu-button` until Home Assistant has assigned `hass`; HA's component + reads `this.hass.kioskMode` in `willUpdate` and would throw before the property was set. + +### Changed + +- **Side-panel domain service calls thread `config_entry_id`** — Circuit horizon, sub-device horizon, and circuit threshold service calls now route to the + originating panel's config entry. Required for cross-panel Favorites edits to target the right panel and fixes the same-panel bug above. +- **W/A unit toggle moved to the persistent header** — The duplicate toggle below the search bar was removed since the persistent panel-stats header now owns + it. The Favorites pseudo-panel's summary strip carries its own toggle. + ## 0.9.2 ### Added diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js index 1532a14..360e073 100644 --- a/dist/span-panel-card.js +++ b/dist/span-panel-card.js @@ -36,7 +36,7 @@ const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:F},ke=(e=ze * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Pe(e){return Ae({...e,state:!0,attribute:!1})}const Me={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Me[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Te(e){return De.unit(e)}function Ie(e){return(e<0?"-":"")+De.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Fe(e){return Math.ceil(e/2)}function Re(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Fe(t)===Fe(i)?"row-span":Re(t)===Re(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${Ie(_)}${Te(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?m:"#555",M=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${M}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${Ie(_)}${Te(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${Ie(n)} ${Te(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Ie(h)}${Te(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${Ie(n)}${Te(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Mt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}async function Tt(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}async function It(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}const Ht=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);function Ft(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Rt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Tt(this._hass,i):await It(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=Ft(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Tt(this._hass,t):await It(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=Ft(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i=t.subDeviceId;"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:i}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of Ht){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Rt)}catch{}const Ot=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let jt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re` + */function Pe(e){return Ae({...e,state:!0,attribute:!1})}const Me={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Me[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Te(e){return De.unit(e)}function Ie(e){return(e<0?"-":"")+De.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Fe(e){return Math.ceil(e/2)}function Re(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Fe(t)===Fe(i)?"row-span":Re(t)===Re(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${Ie(_)}${Te(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?m:"#555",M=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${M}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${Ie(_)}${Te(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${Ie(n)} ${Te(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Ie(h)}${Te(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${Ie(n)}${Te(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Mt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}async function Tt(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}async function It(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}const Ht=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);function Ft(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Rt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Tt(this._hass,i):await It(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=Ft(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Tt(this._hass,t):await It(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=Ft(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of Ht){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Rt)}catch{}const Ot=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let jt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re` (...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}async function Fe(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}async function He(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}class Oe{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Re(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const qe=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);function je(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Ue extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Fe(this._hass,i):await He(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=je(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Fe(this._hass,t):await He(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=je(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i=t.subDeviceId;"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",{subdevice_id:i}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{subdevice_id:i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of qe){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ue)}catch{}async function Ge(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function Ve(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ge(e,i),{topology:i,panelDevice:r,panelSize:s}}function We(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Be=u.power;function Qe(e){return Be.unit(e)}function Je(e){return(e<0?"-":"")+Be.format(e)}function Xe(e){return(Math.abs(e)/1e3).toFixed(1)}function Ke(e){return Math.ceil(e/2)}function Ze(e){return e%2==0?1:0}function Ye(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ke(t)===Ke(n)?"row-span":Ze(t)===Ze(n)?"col-span":"row-span"}function et(e){const t=e.chart_metric??i;return u[t]??u[i]}function tt(e,t){const n=function(e){return et(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class nt{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function it(e,t){return e?.circuits?e.circuits[t]??null:null}function st(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function ot(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=et(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${Je(v)}${Qe(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function at(e,t){return`\n
\n \n
\n `}const rt={names:["power","battery power"],suffixes:["_power"]},lt={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},ct={names:["state of energy"],suffixes:["_soe_kwh"]},dt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function ht(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function pt(e){return ht(e,rt)}function ut(e){return ht(e,lt)}function gt(e){return ht(e,ct)}function _t(e){return ht(e,dt)}function ft(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=pt(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?ut(s):null,v=g?gt(s):null,m=g?_t(s):null,b=vt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=mt(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${Je(u)} ${Qe(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function vt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function mt(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function bt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function yt(e){const t=o[e];return t?t.ms:o[s].ms}function wt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function xt(e){return Math.max(500,Math.floor(e/5e3))}function $t(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function St(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function Ct(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function Et(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=wt(i),l=xt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,St(t,r,l))}}}function kt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:pt(i)};i.type===c&&(e.soc=ut(i),e.soe=gt(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function zt(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=tt(i,n);if(!t)continue;let o;o=s&&s.has(e)?yt(s.get(e)):bt(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of kt(t)){let t;t=o&&o.has(s)?yt(o.get(s)):bt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(Ct(e,n.entityIds,n.uuidByEntity,t,i)):r.push(Et(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function At(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function Pt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=bt(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Xe(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Xe(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Xe(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Xe(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=et(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${Je(f)}${Qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?yt(a.get(s)):c,p=d.device_type===l;At(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class Mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function Tt(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function It(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Nt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new nt,this.graphSettingsCache=new Mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,Tt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,It(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await zt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=tt(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=yt(i),d=wt(c),h=xt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of kt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await zt(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(Pt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=bt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=pt(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${Je(i)} ${Qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");At(e,t,r,o?.has(i)?yt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Dt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class Lt{constructor(){this._ctrl=new Nt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Ve(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=We(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ye(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ke(Math.max(...n));0===Ze(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?it(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=ot(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=at(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=ot(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=at(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=ot(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ft(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Ft="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Ot="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Rt="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",qt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function jt(e,t,n,i,s){return`\n ${i}\n `}class Ut{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function Gt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Vt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=et(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Je(h)}${Qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Wt(e,t,n,i,s,o){const a=ot(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Bt(e){return`
${Ne(e)}
`}function Qt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Xt(e,t,n){return e.sort((e,i)=>{const s=Qt(e[1],t,n),o=Qt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Kt(e){return e.entities?.current??e.entities?.power??""}class Zt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Xt(Object.entries(n.circuits),t,i);let r=o+Gt(this._searchQuery);r+='
';for(const[e,n]of a){const o=it(s,Kt(n)),a=Jt(n,t),l=this._expandedUuids.has(e);r+=Vt(e,n,t,i,o,a,l),l&&(r+=Wt(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+Gt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Xt(n,t,s);d+=Bt(e);for(const[e,n]of i){const i=it(o,Kt(n)),a=Jt(n,t),r=this._expandedUuids.has(e);d+=Vt(e,n,t,s,i,a,r),r&&(d+=Wt(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=et(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${Je(i)}${Qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=it(this._monitoringStatus,Kt(i)),o=Jt(i,this._hass),a=Wt(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Yt(e,t){return`${e}|${t}`}class en{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await Ve(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Yt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Yt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const tn="favorites",nn="span_panel_favorites_view_state";function sn(e){try{localStorage.setItem(nn,JSON.stringify(e))}catch{}}let on=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new Lt,this._monitoringTab=new Ut,this._listDashCtrl=new Nt,this._listCtrl=new Zt(this._listDashCtrl),this._favCache=new Oe,this._favCtrl=new en,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe` + */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}async function Fe(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}async function He(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}class Oe{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Re(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const qe=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);function je(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Ue extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Fe(this._hass,i):await He(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=je(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Fe(this._hass,t):await He(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=je(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of qe){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ue)}catch{}async function Ge(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function Ve(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ge(e,i),{topology:i,panelDevice:r,panelSize:s}}function We(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Be=u.power;function Qe(e){return Be.unit(e)}function Je(e){return(e<0?"-":"")+Be.format(e)}function Xe(e){return(Math.abs(e)/1e3).toFixed(1)}function Ke(e){return Math.ceil(e/2)}function Ze(e){return e%2==0?1:0}function Ye(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ke(t)===Ke(n)?"row-span":Ze(t)===Ze(n)?"col-span":"row-span"}function et(e){const t=e.chart_metric??i;return u[t]??u[i]}function tt(e,t){const n=function(e){return et(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class nt{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function it(e,t){return e?.circuits?e.circuits[t]??null:null}function st(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function ot(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=et(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${Je(v)}${Qe(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function at(e,t){return`\n
\n \n
\n `}const rt={names:["power","battery power"],suffixes:["_power"]},lt={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},ct={names:["state of energy"],suffixes:["_soe_kwh"]},dt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function ht(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function pt(e){return ht(e,rt)}function ut(e){return ht(e,lt)}function gt(e){return ht(e,ct)}function _t(e){return ht(e,dt)}function ft(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=pt(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?ut(s):null,v=g?gt(s):null,m=g?_t(s):null,b=vt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=mt(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${Je(u)} ${Qe(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function vt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function mt(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function bt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function yt(e){const t=o[e];return t?t.ms:o[s].ms}function wt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function xt(e){return Math.max(500,Math.floor(e/5e3))}function $t(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function St(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function Ct(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function Et(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=wt(i),l=xt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,St(t,r,l))}}}function kt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:pt(i)};i.type===c&&(e.soc=ut(i),e.soe=gt(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function zt(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=tt(i,n);if(!t)continue;let o;o=s&&s.has(e)?yt(s.get(e)):bt(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of kt(t)){let t;t=o&&o.has(s)?yt(o.get(s)):bt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(Ct(e,n.entityIds,n.uuidByEntity,t,i)):r.push(Et(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function At(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function Pt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=bt(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Xe(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Xe(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Xe(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Xe(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=et(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${Je(f)}${Qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?yt(a.get(s)):c,p=d.device_type===l;At(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class Mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function Tt(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function It(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Nt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new nt,this.graphSettingsCache=new Mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,Tt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,It(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await zt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=tt(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=yt(i),d=wt(c),h=xt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of kt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await zt(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(Pt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=bt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=pt(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${Je(i)} ${Qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");At(e,t,r,o?.has(i)?yt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Dt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class Lt{constructor(){this._ctrl=new Nt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Ve(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=We(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ye(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ke(Math.max(...n));0===Ze(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?it(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=ot(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=at(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=ot(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=at(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=ot(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ft(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Ft="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Ot="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Rt="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",qt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function jt(e,t,n,i,s){return`\n ${i}\n `}class Ut{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function Gt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Vt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=et(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Je(h)}${Qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Wt(e,t,n,i,s,o){const a=ot(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Bt(e){return`
${Ne(e)}
`}function Qt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Xt(e,t,n){return e.sort((e,i)=>{const s=Qt(e[1],t,n),o=Qt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Kt(e){return e.entities?.current??e.entities?.power??""}class Zt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Xt(Object.entries(n.circuits),t,i);let r=o+Gt(this._searchQuery);r+='
';for(const[e,n]of a){const o=it(s,Kt(n)),a=Jt(n,t),l=this._expandedUuids.has(e);r+=Vt(e,n,t,i,o,a,l),l&&(r+=Wt(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+Gt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Xt(n,t,s);d+=Bt(e);for(const[e,n]of i){const i=it(o,Kt(n)),a=Jt(n,t),r=this._expandedUuids.has(e);d+=Vt(e,n,t,s,i,a,r),r&&(d+=Wt(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=et(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${Je(i)}${Qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=it(this._monitoringStatus,Kt(i)),o=Jt(i,this._hass),a=Wt(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Yt(e,t){return`${e}|${t}`}class en{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await Ve(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Yt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Yt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const tn="favorites",nn="span_panel_favorites_view_state";function sn(e){try{localStorage.setItem(nn,JSON.stringify(e))}catch{}}let on=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new Lt,this._monitoringTab=new Ut,this._listDashCtrl=new Nt,this._listCtrl=new Zt(this._listDashCtrl),this._favCache=new Oe,this._favCtrl=new en,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe`
diff --git a/src/core/side-panel.ts b/src/core/side-panel.ts index 15b94a5..664d679 100644 --- a/src/core/side-panel.ts +++ b/src/core/side-panel.ts @@ -921,19 +921,22 @@ class SpanSidePanel extends HTMLElement { if (btn.classList.contains("active")) return; const subDeviceId = cfg.subDeviceId; + // Without ``config_entry_id`` the backend's _get_horizon_manager + // falls back to the FIRST loaded SPAN entry's manager — wrong + // panel when more than one is configured. The panel-mode list + // and circuit-mode side panel both pass it; thread it here too. + const baseData: Record = { subdevice_id: subDeviceId }; + if (cfg.configEntryId) baseData.config_entry_id = cfg.configEntryId; if (key === "global") { updateSegmentStates("global"); - this._callDomainService("clear_subdevice_graph_horizon", { subdevice_id: subDeviceId }) + this._callDomainService("clear_subdevice_graph_horizon", baseData) .then(() => { this.dispatchEvent(new CustomEvent("graph-settings-changed", { bubbles: true, composed: true })); }) .catch((err: Error) => this._showError(`${t("sidepanel.clear_graph_horizon_failed")} ${err.message ?? err}`)); } else { updateSegmentStates(key); - this._callDomainService("set_subdevice_graph_horizon", { - subdevice_id: subDeviceId, - horizon: key, - }) + this._callDomainService("set_subdevice_graph_horizon", { ...baseData, horizon: key }) .then(() => { this.dispatchEvent(new CustomEvent("graph-settings-changed", { bubbles: true, composed: true })); }) From 4767f0fd0fb664490d87741a6e859533fdc3a98b Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Tue, 14 Apr 2026 23:56:50 -0700 Subject: [PATCH 03/97] fix: re-render Favorites view when a target is un-favorited In the Favorites view, un-favoriting a circuit or sub-device used to leave the row/tile in the rendered list until the next panel or tab switch. _refreshFavorites was deliberately skipping _scheduleTabRender to keep the open Graph Settings side panel alive on real panels. Branch the behavior by context: re-render when in the Favorites view (the user just removed what they were inspecting, so tearing down the side panel as a side effect is acceptable), keep the no-re-render behavior on real panels so the Graph Settings side panel stays open while toggling multiple hearts in a row. --- dist/span-panel.js | 6 +++--- src/panel/span-panel.ts | 22 ++++++++++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/dist/span-panel.js b/dist/span-panel.js index 260b87a..d122be8 100644 --- a/dist/span-panel.js +++ b/dist/span-panel.js @@ -15,7 +15,7 @@ const m=globalThis,b=m.ShadowRoot&&(void 0===m.ShadyCSS||m.ShadyCSS.nativeShadow * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const O=globalThis,R=e=>e,q=O.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ne=/'/g,ie=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ie:ne):a===ie||a===ne?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?n+W:c>=0?(i.push(r),n.slice(0,c)+U+n.slice(c)+G+h):n+G+(-2===c?t:h)}return[de(e,o+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class pe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,n),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=ce.nextNode())&&r.length0){i.textContent=q?q.emptyScript:"";for(let n=0;nX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=pe.createElement(de(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ge(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new _e(this.O(Q()),this.O(Q()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=re}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const i=e;let a,r;for(e=s[0],a=0;ae,q=R.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ne=/'/g,ie=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ie:ne):a===ie||a===ne?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?n+W:c>=0?(i.push(r),n.slice(0,c)+U+n.slice(c)+G+h):n+G+(-2===c?t:h)}return[de(e,o+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class pe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,n),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=ce.nextNode())&&r.length0){i.textContent=q?q.emptyScript:"";for(let n=0;nX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=pe.createElement(de(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ge(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new _e(this.O(Q()),this.O(Q()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=re}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const i=e;let a,r;for(e=s[0],a=0;a(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}async function Fe(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}async function He(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}class Oe{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Re(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const qe=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);function je(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Ue extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Fe(this._hass,i):await He(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=je(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Fe(this._hass,t):await He(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=je(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of qe){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ue)}catch{}async function Ge(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function Ve(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ge(e,i),{topology:i,panelDevice:r,panelSize:s}}function We(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Be=u.power;function Qe(e){return Be.unit(e)}function Je(e){return(e<0?"-":"")+Be.format(e)}function Xe(e){return(Math.abs(e)/1e3).toFixed(1)}function Ke(e){return Math.ceil(e/2)}function Ze(e){return e%2==0?1:0}function Ye(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ke(t)===Ke(n)?"row-span":Ze(t)===Ze(n)?"col-span":"row-span"}function et(e){const t=e.chart_metric??i;return u[t]??u[i]}function tt(e,t){const n=function(e){return et(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class nt{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function it(e,t){return e?.circuits?e.circuits[t]??null:null}function st(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function ot(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=et(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${Je(v)}${Qe(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function at(e,t){return`\n
\n \n
\n `}const rt={names:["power","battery power"],suffixes:["_power"]},lt={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},ct={names:["state of energy"],suffixes:["_soe_kwh"]},dt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function ht(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function pt(e){return ht(e,rt)}function ut(e){return ht(e,lt)}function gt(e){return ht(e,ct)}function _t(e){return ht(e,dt)}function ft(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=pt(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?ut(s):null,v=g?gt(s):null,m=g?_t(s):null,b=vt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=mt(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${Je(u)} ${Qe(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function vt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function mt(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function bt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function yt(e){const t=o[e];return t?t.ms:o[s].ms}function wt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function xt(e){return Math.max(500,Math.floor(e/5e3))}function $t(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function St(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function Ct(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function Et(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=wt(i),l=xt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,St(t,r,l))}}}function kt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:pt(i)};i.type===c&&(e.soc=ut(i),e.soe=gt(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function zt(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=tt(i,n);if(!t)continue;let o;o=s&&s.has(e)?yt(s.get(e)):bt(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of kt(t)){let t;t=o&&o.has(s)?yt(o.get(s)):bt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(Ct(e,n.entityIds,n.uuidByEntity,t,i)):r.push(Et(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function At(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function Pt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=bt(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Xe(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Xe(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Xe(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Xe(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=et(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${Je(f)}${Qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?yt(a.get(s)):c,p=d.device_type===l;At(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class Mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function Tt(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function It(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Nt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new nt,this.graphSettingsCache=new Mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,Tt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,It(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await zt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=tt(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=yt(i),d=wt(c),h=xt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of kt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await zt(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(Pt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=bt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=pt(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${Je(i)} ${Qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");At(e,t,r,o?.has(i)?yt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Dt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class Lt{constructor(){this._ctrl=new Nt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Ve(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=We(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ye(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ke(Math.max(...n));0===Ze(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?it(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=ot(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=at(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=ot(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=at(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=ot(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ft(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Ft="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Ot="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Rt="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",qt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function jt(e,t,n,i,s){return`\n ${i}\n `}class Ut{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function Gt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Vt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=et(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Je(h)}${Qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Wt(e,t,n,i,s,o){const a=ot(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Bt(e){return`
${Ne(e)}
`}function Qt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Xt(e,t,n){return e.sort((e,i)=>{const s=Qt(e[1],t,n),o=Qt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Kt(e){return e.entities?.current??e.entities?.power??""}class Zt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Xt(Object.entries(n.circuits),t,i);let r=o+Gt(this._searchQuery);r+='
';for(const[e,n]of a){const o=it(s,Kt(n)),a=Jt(n,t),l=this._expandedUuids.has(e);r+=Vt(e,n,t,i,o,a,l),l&&(r+=Wt(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+Gt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Xt(n,t,s);d+=Bt(e);for(const[e,n]of i){const i=it(o,Kt(n)),a=Jt(n,t),r=this._expandedUuids.has(e);d+=Vt(e,n,t,s,i,a,r),r&&(d+=Wt(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=et(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${Je(i)}${Qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=it(this._monitoringStatus,Kt(i)),o=Jt(i,this._hass),a=Wt(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Yt(e,t){return`${e}|${t}`}class en{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await Ve(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Yt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Yt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const tn="favorites",nn="span_panel_favorites_view_state";function sn(e){try{localStorage.setItem(nn,JSON.stringify(e))}catch{}}let on=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new Lt,this._monitoringTab=new Ut,this._listDashCtrl=new Nt,this._listCtrl=new Zt(this._listDashCtrl),this._favCache=new Oe,this._favCtrl=new en,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe` + */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}async function Fe(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}async function He(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}class Re{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Oe(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const qe=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);function je(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Ue extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Fe(this._hass,i):await He(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=je(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Fe(this._hass,t):await He(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=je(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of qe){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ue)}catch{}async function Ge(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function Ve(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ge(e,i),{topology:i,panelDevice:r,panelSize:s}}function We(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Be=u.power;function Qe(e){return Be.unit(e)}function Je(e){return(e<0?"-":"")+Be.format(e)}function Xe(e){return(Math.abs(e)/1e3).toFixed(1)}function Ke(e){return Math.ceil(e/2)}function Ze(e){return e%2==0?1:0}function Ye(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ke(t)===Ke(n)?"row-span":Ze(t)===Ze(n)?"col-span":"row-span"}function et(e){const t=e.chart_metric??i;return u[t]??u[i]}function tt(e,t){const n=function(e){return et(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class nt{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function it(e,t){return e?.circuits?e.circuits[t]??null:null}function st(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function ot(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=et(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${Je(v)}${Qe(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function at(e,t){return`\n
\n \n
\n `}const rt={names:["power","battery power"],suffixes:["_power"]},lt={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},ct={names:["state of energy"],suffixes:["_soe_kwh"]},dt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function ht(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function pt(e){return ht(e,rt)}function ut(e){return ht(e,lt)}function gt(e){return ht(e,ct)}function _t(e){return ht(e,dt)}function ft(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=pt(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?ut(s):null,v=g?gt(s):null,m=g?_t(s):null,b=vt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=mt(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${Je(u)} ${Qe(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function vt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function mt(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function bt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function yt(e){const t=o[e];return t?t.ms:o[s].ms}function wt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function xt(e){return Math.max(500,Math.floor(e/5e3))}function $t(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function St(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function Ct(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function Et(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=wt(i),l=xt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,St(t,r,l))}}}function kt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:pt(i)};i.type===c&&(e.soc=ut(i),e.soe=gt(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function zt(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=tt(i,n);if(!t)continue;let o;o=s&&s.has(e)?yt(s.get(e)):bt(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of kt(t)){let t;t=o&&o.has(s)?yt(o.get(s)):bt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(Ct(e,n.entityIds,n.uuidByEntity,t,i)):r.push(Et(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function At(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function Pt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=bt(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Xe(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Xe(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Xe(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Xe(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=et(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${Je(f)}${Qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?yt(a.get(s)):c,p=d.device_type===l;At(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class Mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function Tt(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function It(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Nt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new nt,this.graphSettingsCache=new Mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,Tt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,It(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await zt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=tt(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=yt(i),d=wt(c),h=xt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of kt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await zt(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(Pt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=bt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=pt(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${Je(i)} ${Qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");At(e,t,r,o?.has(i)?yt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Dt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class Lt{constructor(){this._ctrl=new Nt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Ve(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=We(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ye(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ke(Math.max(...n));0===Ze(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?it(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=ot(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=at(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=ot(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=at(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=ot(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ft(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Ft="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Rt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ot="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",qt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function jt(e,t,n,i,s){return`\n ${i}\n `}class Ut{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function Gt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Vt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=et(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Je(h)}${Qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Wt(e,t,n,i,s,o){const a=ot(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Bt(e){return`
${Ne(e)}
`}function Qt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Xt(e,t,n){return e.sort((e,i)=>{const s=Qt(e[1],t,n),o=Qt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Kt(e){return e.entities?.current??e.entities?.power??""}class Zt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Xt(Object.entries(n.circuits),t,i);let r=o+Gt(this._searchQuery);r+='
';for(const[e,n]of a){const o=it(s,Kt(n)),a=Jt(n,t),l=this._expandedUuids.has(e);r+=Vt(e,n,t,i,o,a,l),l&&(r+=Wt(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+Gt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Xt(n,t,s);d+=Bt(e);for(const[e,n]of i){const i=it(o,Kt(n)),a=Jt(n,t),r=this._expandedUuids.has(e);d+=Vt(e,n,t,s,i,a,r),r&&(d+=Wt(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=et(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${Je(i)}${Qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=it(this._monitoringStatus,Kt(i)),o=Jt(i,this._hass),a=Wt(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Yt(e,t){return`${e}|${t}`}class en{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await Ve(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Yt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Yt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const tn="favorites",nn="span_panel_favorites_view_state";function sn(e){try{localStorage.setItem(nn,JSON.stringify(e))}catch{}}let on=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new Lt,this._monitoringTab=new Ut,this._listDashCtrl=new Nt,this._listCtrl=new Zt(this._listDashCtrl),this._favCache=new Re,this._favCtrl=new en,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe`
@@ -95,7 +95,7 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce
${"Loading…"}
- `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===tn}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,sn(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,sn(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==tn).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(nn);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===tn){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Re(t))return e;return[{id:tn,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){this._favCache.invalidate();const e=await this._loadFavorites(),t=this._selectedPanelId===tn;this._favorites=e;const n=this._panels.filter(e=>e.id!==tn);if(this._panels=this._buildPanelList(n,e),t&&!Re(e)){!function(){try{localStorage.removeItem(nn)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView||this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return We(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=Object.values(this._favorites).filter(e=>(e.circuits?.length??0)>0||(e.sub_devices?.length??0)>0).length,t=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),i=n(1===t?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(t)).replace("{panels}",String(e)),s="current"===(this._chartMetric||"power");return`\n
\n
${Ne(n("panel.favorites"))}
\n
${Ne(i)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await Ge(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==tn),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ft(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const o=document.createElement("h3");o.style.margin="8px 0 12px",o.style.fontSize="1em",o.textContent=t?.name_by_user??t?.name??e,n.appendChild(o);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const r=new Ut;this._favoritesMonitoringTabs.set(e,r),await r.render(a,this.hass,e)}}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};on.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` + `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===tn}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,sn(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,sn(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==tn).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(nn);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===tn){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Oe(t))return e;return[{id:tn,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){this._favCache.invalidate();const e=await this._loadFavorites(),t=this._selectedPanelId===tn;this._favorites=e;const n=this._panels.filter(e=>e.id!==tn);if(this._panels=this._buildPanelList(n,e),t&&!Oe(e)){!function(){try{localStorage.removeItem(nn)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return We(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=Object.values(this._favorites).filter(e=>(e.circuits?.length??0)>0||(e.sub_devices?.length??0)>0).length,t=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),i=n(1===t?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(t)).replace("{panels}",String(e)),s="current"===(this._chartMetric||"power");return`\n
\n
${Ne(n("panel.favorites"))}
\n
${Ne(i)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await Ge(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==tn),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ft(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const o=document.createElement("h3");o.style.margin="8px 0 12px",o.style.fontSize="1em",o.textContent=t?.name_by_user??t?.name??e,n.appendChild(o);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const r=new Ut;this._favoritesMonitoringTabs.set(e,r),await r.render(a,this.hass,e)}}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};on.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` :host { color: var(--primary-text-color); } diff --git a/src/panel/span-panel.ts b/src/panel/span-panel.ts index f6457df..694771f 100644 --- a/src/panel/span-panel.ts +++ b/src/panel/span-panel.ts @@ -569,11 +569,17 @@ export class SpanPanelElement extends LitElement { } /** - * React to a ``favorites-changed`` event dispatched by the side panel. - * Re-fetches the favorites map and updates the dropdown entry + the - * per-panel favorites passed into controllers. Does NOT tear down the - * tab content — that would close any open side panel. The next panel - * or tab switch naturally picks up the new list for the Favorites view. + * React to a ``favorites-changed`` event dispatched by a heart toggle + * in the side panel. Re-fetches the favorites map and updates the + * dropdown entry. Re-renders the tab only when needed: + * + * - Favorites view: always re-render so removed targets disappear + * immediately. The open side panel is destroyed as a side effect, + * which is acceptable UX since the user just un-favorited the + * target they were inspecting. + * - Real panel view: skip the re-render so the open Graph Settings + * side panel stays interactive while the user toggles hearts on + * multiple targets in a row. */ private async _refreshFavorites(): Promise { this._favCache.invalidate(); @@ -598,7 +604,11 @@ export class SpanPanelElement extends LitElement { } else { this._selectedPanelId = null; } - } else if (!this._isFavoritesView) { + } else if (this._isFavoritesView) { + // Re-render the favorites view so newly un-favorited rows / + // sub-device tiles are removed from the list. + this._scheduleTabRender(); + } else { // Keep per-panel favorites fresh so the next gear click (or a // re-opened side panel) reflects the current heart state. this._applyPanelFavorites(); From 611c8048cc5887af0d7622c61c8b9b321509dd77 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Wed, 15 Apr 2026 00:04:28 -0700 Subject: [PATCH 04/97] fix: replace Favorite ha-switch with heart icon to avoid breaker confusion The per-circuit and per-sub-device side panels rendered the Favorite section with an ha-switch that sat directly under the breaker relay switch. Visually similar; accidentally hitting the wrong one could trip a breaker. Replaced both with the same filled/outlined heart icon used in the Graph Settings list. The two render paths now share a single _appendFavoriteHeartSection helper. --- dist/span-panel-card.js | 12 +++--- dist/span-panel.js | 6 +-- src/core/side-panel.ts | 84 ++++++++++++----------------------------- 3 files changed, 33 insertions(+), 69 deletions(-) diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js index 360e073..fe12263 100644 --- a/dist/span-panel-card.js +++ b/dist/span-panel-card.js @@ -4,12 +4,12 @@ let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_ac * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const b=globalThis,y=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,w=Symbol(),x=new WeakMap;let S=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==w)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(y&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=x.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&x.set(t,e))}return e}toString(){return this.cssText}};const C=e=>new S("string"==typeof e?e:e+"",void 0,w),E=y?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return C(t)})(e):e,{is:$,defineProperty:z,getOwnPropertyDescriptor:k,getOwnPropertyNames:A,getOwnPropertySymbols:P,getPrototypeOf:M}=Object,L=globalThis,N=L.trustedTypes,D=N?N.emptyScript:"",T=L.reactiveElementPolyfillSupport,I=(e,t)=>e,H={toAttribute(e,t){switch(t){case Boolean:e=e?D:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},F=(e,t)=>!$(e,t),R={attribute:!0,type:String,converter:H,reflect:!1,useDefault:!1,hasChanged:F}; +const b=globalThis,y=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,w=Symbol(),x=new WeakMap;let S=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==w)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(y&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=x.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&x.set(t,e))}return e}toString(){return this.cssText}};const C=e=>new S("string"==typeof e?e:e+"",void 0,w),E=y?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return C(t)})(e):e,{is:$,defineProperty:z,getOwnPropertyDescriptor:k,getOwnPropertyNames:A,getOwnPropertySymbols:P,getPrototypeOf:M}=Object,L=globalThis,N=L.trustedTypes,D=N?N.emptyScript:"",I=L.reactiveElementPolyfillSupport,T=(e,t)=>e,H={toAttribute(e,t){switch(t){case Boolean:e=e?D:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},R=(e,t)=>!$(e,t),F={attribute:!0,type:String,converter:H,reflect:!1,useDefault:!1,hasChanged:R}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;let O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=R){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&z(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=k(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??R}static _$Ei(){if(this.hasOwnProperty(I("elementProperties")))return;const e=M(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(I("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(I("properties"))){const e=this.properties,t=[...A(e),...P(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(E(e))}else void 0!==e&&t.push(E(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(y)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=b.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:H).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:H;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??F)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[I("elementProperties")]=new Map,O[I("finalized")]=new Map,T?.({ReactiveElement:O}),(L.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;let O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=F){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&z(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=k(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??F}static _$Ei(){if(this.hasOwnProperty(T("elementProperties")))return;const e=M(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(T("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(T("properties"))){const e=this.properties,t=[...A(e),...P(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(E(e))}else void 0!==e&&t.push(E(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(y)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=b.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:H).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:H;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??R)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[T("elementProperties")]=new Map,O[T("finalized")]=new Map,I?.({ReactiveElement:O}),(L.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC @@ -26,7 +26,7 @@ const j=globalThis,q=e=>e,U=j.trustedTypes,W=U?U.createPolicy("lit-html",{create * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:F},ke=(e=ze,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; +const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:R},ke=(e=ze,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; /** * @license * Copyright 2017 Google LLC @@ -36,7 +36,7 @@ const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:F},ke=(e=ze * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Pe(e){return Ae({...e,state:!0,attribute:!1})}const Me={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Me[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Te(e){return De.unit(e)}function Ie(e){return(e<0?"-":"")+De.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Fe(e){return Math.ceil(e/2)}function Re(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Fe(t)===Fe(i)?"row-span":Re(t)===Re(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${Ie(_)}${Te(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?m:"#555",M=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${M}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${Ie(_)}${Te(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${Ie(n)} ${Te(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Ie(h)}${Te(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${Ie(n)}${Te(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Mt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}async function Tt(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}async function It(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}const Ht=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);function Ft(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Rt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Tt(this._hass,i):await It(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=Ft(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Tt(this._hass,t):await It(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=Ft(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of Ht){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Rt)}catch{}const Ot=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let jt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re` + */function Pe(e){return Ae({...e,state:!0,attribute:!1})}const Me={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Me[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Ie(e){return De.unit(e)}function Te(e){return(e<0?"-":"")+De.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Re(e){return Math.ceil(e/2)}function Fe(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Re(t)===Re(i)?"row-span":Fe(t)===Fe(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${Te(_)}${Ie(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?m:"#555",M=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${M}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${Te(_)}${Ie(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${Te(n)} ${Ie(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Te(h)}${Ie(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${Te(n)}${Ie(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Mt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}const It=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);class Tt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await async function(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i):await async function(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("button");r.type="button",r.className=i?"fav-heart active":"fav-heart",r.dataset.role="favorite-heart",r.title=n("sidepanel.save_to_favorites");const c=document.createElement("ha-icon");c.setAttribute("icon",i?"mdi:heart":"mdi:heart-outline"),r.appendChild(c),r.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(r,c,t).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of It){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Tt)}catch{}const Ht=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let Rt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re`
${Le(n("card.loading"))}
- `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Pt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Mt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Pt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Mt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Pt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Fe(Math.max(...i));0===Re(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${Ie(u)} ${Te(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Ot.map(e=>re` + `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Pt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Mt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Pt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Mt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Pt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Re(Math.max(...i));0===Fe(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${Te(u)} ${Ie(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Ht.map(e=>re`
${e.name} @@ -78,4 +78,4 @@ const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:F},ke=(e=ze
${n("card.no_device")}
- `}};jt.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],jt.prototype,"hass",void 0),v([Pe()],jt.prototype,"_config",void 0),v([Pe()],jt.prototype,"_discovered",void 0),v([Pe()],jt.prototype,"_discovering",void 0),v([Pe()],jt.prototype,"_discoveryError",void 0),v([Pe()],jt.prototype,"_topology",void 0),v([Pe()],jt.prototype,"_activeTab",void 0),jt=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],jt);class qt extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",qt)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); + `}};Rt.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],Rt.prototype,"hass",void 0),v([Pe()],Rt.prototype,"_config",void 0),v([Pe()],Rt.prototype,"_discovered",void 0),v([Pe()],Rt.prototype,"_discovering",void 0),v([Pe()],Rt.prototype,"_discoveryError",void 0),v([Pe()],Rt.prototype,"_topology",void 0),v([Pe()],Rt.prototype,"_activeTab",void 0),Rt=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],Rt);class Ft extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",Ft)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); diff --git a/dist/span-panel.js b/dist/span-panel.js index d122be8..7086a08 100644 --- a/dist/span-panel.js +++ b/dist/span-panel.js @@ -46,7 +46,7 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}async function Fe(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}async function He(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}class Re{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Oe(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const qe=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);function je(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}class Ue extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await Fe(this._hass,i):await He(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=je(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}async _setFavoriteFromToggle(e,t,i){if(this._hass)try{i?await Fe(this._hass,t):await He(this._hass,t)}catch(t){i?(e.removeAttribute("checked"),e.checked=!1):(e.setAttribute("checked",""),e.checked=!0);const s=je(t);throw this._showError(`${n("sidepanel.favorite_failed")} ${s}`),t}}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);if(!i)return;const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("ha-switch");r.dataset.role="favorite-toggle",t.isFavorite&&r.setAttribute("checked",""),r.addEventListener("change",()=>{const e=r.checked;this._setFavoriteFromToggle(r,i,e).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of qe){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ue)}catch{}async function Ge(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function Ve(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await Ge(e,i),{topology:i,panelDevice:r,panelSize:s}}function We(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Be=u.power;function Qe(e){return Be.unit(e)}function Je(e){return(e<0?"-":"")+Be.format(e)}function Xe(e){return(Math.abs(e)/1e3).toFixed(1)}function Ke(e){return Math.ceil(e/2)}function Ze(e){return e%2==0?1:0}function Ye(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Ke(t)===Ke(n)?"row-span":Ze(t)===Ze(n)?"col-span":"row-span"}function et(e){const t=e.chart_metric??i;return u[t]??u[i]}function tt(e,t){const n=function(e){return et(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class nt{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function it(e,t){return e?.circuits?e.circuits[t]??null:null}function st(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function ot(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=et(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${Je(v)}${Qe(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function at(e,t){return`\n
\n \n
\n `}const rt={names:["power","battery power"],suffixes:["_power"]},lt={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},ct={names:["state of energy"],suffixes:["_soe_kwh"]},dt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function ht(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function pt(e){return ht(e,rt)}function ut(e){return ht(e,lt)}function gt(e){return ht(e,ct)}function _t(e){return ht(e,dt)}function ft(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=pt(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?ut(s):null,v=g?gt(s):null,m=g?_t(s):null,b=vt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=mt(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${Je(u)} ${Qe(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function vt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function mt(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function bt(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function yt(e){const t=o[e];return t?t.ms:o[s].ms}function wt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function xt(e){return Math.max(500,Math.floor(e/5e3))}function $t(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function St(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function Ct(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function Et(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=wt(i),l=xt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,St(t,r,l))}}}function kt(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:pt(i)};i.type===c&&(e.soc=ut(i),e.soe=gt(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function zt(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=tt(i,n);if(!t)continue;let o;o=s&&s.has(e)?yt(s.get(e)):bt(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of kt(t)){let t;t=o&&o.has(s)?yt(o.get(s)):bt(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(Ct(e,n.entityIds,n.uuidByEntity,t,i)):r.push(Et(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function At(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function Pt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=bt(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Xe(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Xe(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Xe(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Xe(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=et(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${Je(f)}${Qe(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?yt(a.get(s)):c,p=d.device_type===l;At(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class Mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function Tt(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function It(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Nt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new nt,this.graphSettingsCache=new Mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,Tt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,It(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await zt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=tt(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=yt(i),d=wt(c),h=xt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of kt(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await zt(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(Pt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=bt(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=pt(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${Je(i)} ${Qe(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");At(e,t,r,o?.has(i)?yt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Dt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class Lt{constructor(){this._ctrl=new Nt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await Ve(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=We(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Ye(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Ke(Math.max(...n));0===Ze(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?it(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=ot(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=at(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=ot(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=at(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=ot(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ft(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Ft="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Rt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ot="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",qt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function jt(e,t,n,i,s){return`\n ${i}\n `}class Ut{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${jt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${jt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${jt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${jt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function Gt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function Vt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=et(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Je(h)}${Qe(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Wt(e,t,n,i,s,o){const a=ot(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Bt(e){return`
${Ne(e)}
`}function Qt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Jt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Xt(e,t,n){return e.sort((e,i)=>{const s=Qt(e[1],t,n),o=Qt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Kt(e){return e.entities?.current??e.entities?.power??""}class Zt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Xt(Object.entries(n.circuits),t,i);let r=o+Gt(this._searchQuery);r+='
';for(const[e,n]of a){const o=it(s,Kt(n)),a=Jt(n,t),l=this._expandedUuids.has(e);r+=Vt(e,n,t,i,o,a,l),l&&(r+=Wt(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+Gt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Xt(n,t,s);d+=Bt(e);for(const[e,n]of i){const i=it(o,Kt(n)),a=Jt(n,t),r=this._expandedUuids.has(e);d+=Vt(e,n,t,s,i,a,r),r&&(d+=Wt(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=et(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Qt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${Je(i)}${Qe(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=it(this._monitoringStatus,Kt(i)),o=Jt(i,this._hass),a=Wt(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Yt(e,t){return`${e}|${t}`}class en{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await Ve(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Yt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Yt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const tn="favorites",nn="span_panel_favorites_view_state";function sn(e){try{localStorage.setItem(nn,JSON.stringify(e))}catch{}}let on=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new Lt,this._monitoringTab=new Ut,this._listDashCtrl=new Nt,this._listCtrl=new Zt(this._listDashCtrl),this._favCache=new Re,this._favCtrl=new en,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe` + */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}class Fe{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function He(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const Re=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);class Oe extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await async function(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}(this._hass,i):await async function(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const n=this._favoriteEntityId(t.entities);n&&this._appendFavoriteHeartSection(e,n,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("button");r.type="button",r.className=i?"fav-heart active":"fav-heart",r.dataset.role="favorite-heart",r.title=n("sidepanel.save_to_favorites");const l=document.createElement("ha-icon");l.setAttribute("icon",i?"mdi:heart":"mdi:heart-outline"),r.appendChild(l),r.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(r,l,t).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const n=this._subDeviceFavoriteEntityId(t.entities);n&&this._appendFavoriteHeartSection(e,n,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of Re){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Oe)}catch{}async function qe(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function je(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await qe(e,i),{topology:i,panelDevice:r,panelSize:s}}function Ue(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Ge=u.power;function Ve(e){return Ge.unit(e)}function We(e){return(e<0?"-":"")+Ge.format(e)}function Be(e){return(Math.abs(e)/1e3).toFixed(1)}function Qe(e){return Math.ceil(e/2)}function Je(e){return e%2==0?1:0}function Xe(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Qe(t)===Qe(n)?"row-span":Je(t)===Je(n)?"col-span":"row-span"}function Ke(e){const t=e.chart_metric??i;return u[t]??u[i]}function Ze(e,t){const n=function(e){return Ke(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class Ye{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function et(e,t){return e?.circuits?e.circuits[t]??null:null}function tt(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function nt(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=Ke(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${We(v)}${Ve(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function it(e,t){return`\n
\n \n
\n `}const st={names:["power","battery power"],suffixes:["_power"]},ot={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},at={names:["state of energy"],suffixes:["_soe_kwh"]},rt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function lt(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function ct(e){return lt(e,st)}function dt(e){return lt(e,ot)}function ht(e){return lt(e,at)}function pt(e){return lt(e,rt)}function ut(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=ct(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?dt(s):null,v=g?ht(s):null,m=g?pt(s):null,b=gt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=_t(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${We(u)} ${Ve(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function gt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function _t(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ft(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function vt(e){const t=o[e];return t?t.ms:o[s].ms}function mt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function bt(e){return Math.max(500,Math.floor(e/5e3))}function yt(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function wt(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function xt(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function $t(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=mt(i),l=bt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,wt(t,r,l))}}}function St(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:ct(i)};i.type===c&&(e.soc=dt(i),e.soe=ht(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function Ct(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=Ze(i,n);if(!t)continue;let o;o=s&&s.has(e)?vt(s.get(e)):ft(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of St(t)){let t;t=o&&o.has(s)?vt(o.get(s)):ft(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(xt(e,n.entityIds,n.uuidByEntity,t,i)):r.push($t(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function Et(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function kt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=ft(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Be(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Be(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Be(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Be(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=Ke(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${We(f)}${Ve(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?vt(a.get(s)):c,p=d.device_type===l;Et(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class zt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function At(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function Pt(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Mt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ye,this.graphSettingsCache=new zt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,At(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,Pt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await Ct(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=Ze(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=vt(i),d=mt(c),h=bt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of St(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await Ct(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(kt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=ft(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=ct(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${We(i)} ${Ve(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");Et(e,t,r,o?.has(i)?vt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Tt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class It{constructor(){this._ctrl=new Mt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await je(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=Ue(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Xe(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Qe(Math.max(...n));0===Je(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?et(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=nt(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=it(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=nt(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=it(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=nt(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ut(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Nt="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Dt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Lt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ft="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function Rt(e,t,n,i,s){return`\n ${i}\n `}class Ot{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function qt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function jt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=Ke(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${We(h)}${Ve(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Ut(e,t,n,i,s,o){const a=nt(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Gt(e){return`
${Ne(e)}
`}function Vt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Wt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Bt(e,t,n){return e.sort((e,i)=>{const s=Vt(e[1],t,n),o=Vt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Qt(e){return e.entities?.current??e.entities?.power??""}class Jt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Bt(Object.entries(n.circuits),t,i);let r=o+qt(this._searchQuery);r+='
';for(const[e,n]of a){const o=et(s,Qt(n)),a=Wt(n,t),l=this._expandedUuids.has(e);r+=jt(e,n,t,i,o,a,l),l&&(r+=Ut(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+qt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Bt(n,t,s);d+=Gt(e);for(const[e,n]of i){const i=et(o,Qt(n)),a=Wt(n,t),r=this._expandedUuids.has(e);d+=jt(e,n,t,s,i,a,r),r&&(d+=Ut(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=Ke(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Vt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${We(i)}${Ve(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=et(this._monitoringStatus,Qt(i)),o=Wt(i,this._hass),a=Ut(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Xt(e,t){return`${e}|${t}`}class Kt{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await je(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Xt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Xt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const Zt="favorites",Yt="span_panel_favorites_view_state";function en(e){try{localStorage.setItem(Yt,JSON.stringify(e))}catch{}}let tn=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new It,this._monitoringTab=new Ot,this._listDashCtrl=new Mt,this._listCtrl=new Jt(this._listDashCtrl),this._favCache=new Fe,this._favCtrl=new Kt,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe`
@@ -95,7 +95,7 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce
${"Loading…"}
- `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===tn}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,sn(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,sn(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==tn).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(nn);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===tn){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Oe(t))return e;return[{id:tn,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){this._favCache.invalidate();const e=await this._loadFavorites(),t=this._selectedPanelId===tn;this._favorites=e;const n=this._panels.filter(e=>e.id!==tn);if(this._panels=this._buildPanelList(n,e),t&&!Oe(e)){!function(){try{localStorage.removeItem(nn)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return We(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=Object.values(this._favorites).filter(e=>(e.circuits?.length??0)>0||(e.sub_devices?.length??0)>0).length,t=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),i=n(1===t?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(t)).replace("{panels}",String(e)),s="current"===(this._chartMetric||"power");return`\n
\n
${Ne(n("panel.favorites"))}
\n
${Ne(i)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await Ve(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await Ge(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==tn),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ft(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const o=document.createElement("h3");o.style.margin="8px 0 12px",o.style.fontSize="1em",o.textContent=t?.name_by_user??t?.name??e,n.appendChild(o);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const r=new Ut;this._favoritesMonitoringTabs.set(e,r),await r.render(a,this.hass,e)}}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};on.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` + `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===Zt}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,en(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,en(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==Zt).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(Yt);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===Zt){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!He(t))return e;return[{id:Zt,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){this._favCache.invalidate();const e=await this._loadFavorites(),t=this._selectedPanelId===Zt;this._favorites=e;const n=this._panels.filter(e=>e.id!==Zt);if(this._panels=this._buildPanelList(n,e),t&&!He(e)){!function(){try{localStorage.removeItem(Yt)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return Ue(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=Object.values(this._favorites).filter(e=>(e.circuits?.length??0)>0||(e.sub_devices?.length??0)>0).length,t=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),i=n(1===t?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(t)).replace("{panels}",String(e)),s="current"===(this._chartMetric||"power");return`\n
\n
${Ne(n("panel.favorites"))}
\n
${Ne(i)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await qe(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==Zt),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ut(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const o=document.createElement("h3");o.style.margin="8px 0 12px",o.style.fontSize="1em",o.textContent=t?.name_by_user??t?.name??e,n.appendChild(o);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const r=new Ot;this._favoritesMonitoringTabs.set(e,r),await r.render(a,this.hass,e)}}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};tn.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` :host { color: var(--primary-text-color); } @@ -185,4 +185,4 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce opacity: 1; border-bottom-color: var(--app-header-text-color, white); } - `,v([ke({attribute:!1})],on.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],on.prototype,"narrow",void 0),v([ze()],on.prototype,"_panels",void 0),v([ze()],on.prototype,"_selectedPanelId",void 0),v([ze()],on.prototype,"_activeTab",void 0),v([ze()],on.prototype,"_discovered",void 0),v([ze()],on.prototype,"_discoveryError",void 0),v([ze()],on.prototype,"_chartMetric",void 0),v([ze()],on.prototype,"_favorites",void 0),on=v([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],on),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let an=!1;const rn=on.prototype.connectedCallback;on.prototype.connectedCallback=function(){an=!0,rn.call(this)};const ln=on.prototype.disconnectedCallback;on.prototype.disconnectedCallback=function(){an=!1,ln.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(an||window.location.pathname.includes("span-panel")&&setTimeout(()=>{an||location.reload()},200))}); + `,v([ke({attribute:!1})],tn.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],tn.prototype,"narrow",void 0),v([ze()],tn.prototype,"_panels",void 0),v([ze()],tn.prototype,"_selectedPanelId",void 0),v([ze()],tn.prototype,"_activeTab",void 0),v([ze()],tn.prototype,"_discovered",void 0),v([ze()],tn.prototype,"_discoveryError",void 0),v([ze()],tn.prototype,"_chartMetric",void 0),v([ze()],tn.prototype,"_favorites",void 0),tn=v([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],tn),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let nn=!1;const sn=tn.prototype.connectedCallback;tn.prototype.connectedCallback=function(){nn=!0,sn.call(this)};const on=tn.prototype.disconnectedCallback;tn.prototype.disconnectedCallback=function(){nn=!1,on.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(nn||window.location.pathname.includes("span-panel")&&setTimeout(()=>{nn||location.reload()},200))}); diff --git a/src/core/side-panel.ts b/src/core/side-panel.ts index 664d679..04e6447 100644 --- a/src/core/side-panel.ts +++ b/src/core/side-panel.ts @@ -770,7 +770,16 @@ class SpanSidePanel extends HTMLElement { private _renderFavoriteSection(body: HTMLDivElement, cfg: CircuitModeConfig): void { const entityId = this._favoriteEntityId(cfg.entities); if (!entityId) return; + this._appendFavoriteHeartSection(body, entityId, cfg.isFavorite === true); + } + /** + * Build a Favorite section with a heart icon (filled = favorited, + * outlined = not). Used in both the per-circuit and per-sub-device + * side panels. A heart deliberately avoids the visual confusion of + * placing an ha-switch directly under the breaker relay switch. + */ + private _appendFavoriteHeartSection(body: HTMLDivElement, entityId: string, isFavorite: boolean): void { const section = document.createElement("div"); section.className = "section"; section.innerHTML = ``; @@ -782,48 +791,29 @@ class SpanSidePanel extends HTMLElement { label.className = "field-label"; label.textContent = t("sidepanel.save_to_favorites"); - const toggle = document.createElement("ha-switch") as HaSwitchElement; - toggle.dataset.role = "favorite-toggle"; - if (cfg.isFavorite) toggle.setAttribute("checked", ""); + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = isFavorite ? "fav-heart active" : "fav-heart"; + btn.dataset.role = "favorite-heart"; + btn.title = t("sidepanel.save_to_favorites"); - toggle.addEventListener("change", () => { - // The authoritative state after a user toggle lives on ``checked``; - // ``hasAttribute("checked")`` still reflects the initial render. - const nextActive = toggle.checked; - this._setFavoriteFromToggle(toggle, entityId, nextActive).catch(() => { - // error already displayed + const icon = document.createElement("ha-icon"); + icon.setAttribute("icon", isFavorite ? "mdi:heart" : "mdi:heart-outline"); + btn.appendChild(icon); + + btn.addEventListener("click", (ev: Event) => { + ev.stopPropagation(); + this._toggleFavoriteEntity(btn, icon, entityId).catch(() => { + // error message shown inside _toggleFavoriteEntity }); }); row.appendChild(label); - row.appendChild(toggle); + row.appendChild(btn); section.appendChild(row); body.appendChild(section); } - private async _setFavoriteFromToggle(toggle: HaSwitchElement, entityId: string, nextActive: boolean): Promise { - if (!this._hass) return; - try { - if (nextActive) { - await addFavorite(this._hass, entityId); - } else { - await removeFavorite(this._hass, entityId); - } - } catch (err) { - // Roll back the switch to its prior state. - if (nextActive) { - toggle.removeAttribute("checked"); - toggle.checked = false; - } else { - toggle.setAttribute("checked", ""); - toggle.checked = true; - } - const message = _extractErrorMessage(err); - this._showError(`${t("sidepanel.favorite_failed")} ${message}`); - throw err; - } - } - private _renderSubDeviceMode(panel: HTMLDivElement, cfg: SubDeviceModeConfig): void { const header = this._createHeader(escapeHtml(cfg.name), escapeHtml(cfg.deviceType)); panel.appendChild(header); @@ -847,33 +837,7 @@ class SpanSidePanel extends HTMLElement { private _renderSubDeviceFavoriteSection(body: HTMLDivElement, cfg: SubDeviceModeConfig): void { const entityId = this._subDeviceFavoriteEntityId(cfg.entities); if (!entityId) return; - - const section = document.createElement("div"); - section.className = "section"; - section.innerHTML = ``; - - const row = document.createElement("div"); - row.className = "field-row"; - - const label = document.createElement("span"); - label.className = "field-label"; - label.textContent = t("sidepanel.save_to_favorites"); - - const toggle = document.createElement("ha-switch") as HaSwitchElement; - toggle.dataset.role = "favorite-toggle"; - if (cfg.isFavorite) toggle.setAttribute("checked", ""); - - toggle.addEventListener("change", () => { - const nextActive = toggle.checked; - this._setFavoriteFromToggle(toggle, entityId, nextActive).catch(() => { - // error already displayed - }); - }); - - row.appendChild(label); - row.appendChild(toggle); - section.appendChild(row); - body.appendChild(section); + this._appendFavoriteHeartSection(body, entityId, cfg.isFavorite === true); } private _renderSubDeviceHorizonSection(body: HTMLDivElement, cfg: SubDeviceModeConfig): void { From fea70b4264bb61bab5f2a10a3500a049c5e2379a Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Wed, 15 Apr 2026 00:37:24 -0700 Subject: [PATCH 05/97] fix: code review hardening for Favorites view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses findings from the deep code review of the favorites branch. Critical fixes: - Per-entry horizon resolution in Favorites view. ``onGraphSettingsChanged`` and ``fetchAndBuildHorizonMaps`` now branch on ``_favRefs``; in favorites mode they fetch graph settings per contributing config entry in parallel and route each composite circuit/sub-device id through its ``FavoriteRef`` to the originating entry's settings. Without this, a per-target horizon override on a non-primary panel was masked by the primary entry's settings cache. - Refresh-token guard in ``_refreshFavorites``: a monotonic ``_refreshSeq`` causes superseded callbacks to bail out, preventing rapid heart toggles from interleaving renders or scheduling duplicate tab rebuilds. - ``_renderFavoritesMonitoring`` builds tabs into a local map and only commits to the instance field after the loop, with per-panel try/catch so a single failing entry can't orphan tabs from the cleanup loop. UX / a11y / cleanup: - Heart buttons are now ``role=switch`` with ``aria-pressed`` and ``aria-label``; ``_toggleFavoriteEntity`` syncs ``aria-pressed`` alongside the optimistic class flip. Single ``_buildHeartButton`` helper used by both circuit/sub-device panel rows and the per-target side-panel Favorite section. - Favorites summary uses explicit ``t("panel.favorites_summary_one")``/ ``t("panel.favorites_summary_many")`` so the i18n validator no longer reports them unused; messages dropped the ungrammatical "across N panels" suffix and now read "1 favorite" / "{circuits} favorites". - ``_renderFavoritesMonitoring`` heading uses ``h2`` to fit the document outline. - Comment on ``PanelModeConfig.favoriteCircuitUuids`` / ``favoriteSubDeviceIds`` documents that they are open-time snapshots, not live — gear re-clicks rebuild from ``_panelFavorites``. - ``_buildFavoriteHeart`` warns to console when a circuit has no current/power sensor (heart silently suppressed otherwise). Dead code removed: - ``parseCompositeId`` (exported but unused). - ``FavoritesBuildResult.panelTopologies`` (built but not consumed). --- dist/span-panel-card.js | 14 +++---- dist/span-panel.js | 24 +++++------ src/core/dashboard-controller.ts | 57 ++++++++++++++++++++++--- src/core/favorites-controller.ts | 23 ----------- src/core/side-panel.ts | 71 ++++++++++++++------------------ src/i18n.ts | 20 ++++----- src/panel/span-panel.ts | 40 ++++++++++++++---- 7 files changed, 144 insertions(+), 105 deletions(-) diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js index fe12263..d6d9d19 100644 --- a/dist/span-panel-card.js +++ b/dist/span-panel-card.js @@ -1,15 +1,15 @@ -let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 circuit across {panels} panels","panel.favorites_summary_many":"{circuits} circuits across {panels} panels","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito en {panels} paneles","panel.favorites_summary_many":"{circuits} circuitos en {panels} paneles","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 circuit sur {panels} panneaux","panel.favorites_summary_many":"{circuits} circuits sur {panels} panneaux","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"{panels} パネルにわたる 1 回路","panel.favorites_summary_many":"{panels} パネルにわたる {circuits} 回路","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito em {panels} painéis","panel.favorites_summary_many":"{circuits} circuitos em {panels} painéis","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function i(i){e=i&&t[i]?i:"en"}function n(i){return t[e]?.[i]??t.en?.[i]??i}const s="power",o="5m",a={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},r="span_panel",c="CLOSED",l="pv",d="bess",h="evse",p="sub_",u=500,g={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},_={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:g.power},f={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},m="#ff9800";function v(e,t,i,n){var s,o=arguments.length,a=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,n);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,i,a):s(t,i))||a);return o>3&&a&&Object.defineProperty(t,i,a),a}"function"==typeof SuppressedError&&SuppressedError; +let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 favorite","panel.favorites_summary_many":"{circuits} favorites","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 favori","panel.favorites_summary_many":"{circuits} favoris","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"お気に入り 1 件","panel.favorites_summary_many":"お気に入り {circuits} 件","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function i(i){e=i&&t[i]?i:"en"}function n(i){return t[e]?.[i]??t.en?.[i]??i}const s="power",o="5m",a={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},r="span_panel",c="CLOSED",l="pv",d="bess",h="evse",p="sub_",u=500,g={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},_={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:g.power},f={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},m="#ff9800";function v(e,t,i,n){var s,o=arguments.length,a=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,n);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,i,a):s(t,i))||a);return o>3&&a&&Object.defineProperty(t,i,a),a}"function"==typeof SuppressedError&&SuppressedError; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const b=globalThis,y=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,w=Symbol(),x=new WeakMap;let S=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==w)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(y&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=x.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&x.set(t,e))}return e}toString(){return this.cssText}};const C=e=>new S("string"==typeof e?e:e+"",void 0,w),E=y?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return C(t)})(e):e,{is:$,defineProperty:z,getOwnPropertyDescriptor:k,getOwnPropertyNames:A,getOwnPropertySymbols:P,getPrototypeOf:M}=Object,L=globalThis,N=L.trustedTypes,D=N?N.emptyScript:"",I=L.reactiveElementPolyfillSupport,T=(e,t)=>e,H={toAttribute(e,t){switch(t){case Boolean:e=e?D:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},R=(e,t)=>!$(e,t),F={attribute:!0,type:String,converter:H,reflect:!1,useDefault:!1,hasChanged:R}; +const b=globalThis,y=b.ShadowRoot&&(void 0===b.ShadyCSS||b.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,w=Symbol(),x=new WeakMap;let S=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==w)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(y&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=x.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&x.set(t,e))}return e}toString(){return this.cssText}};const C=e=>new S("string"==typeof e?e:e+"",void 0,w),E=y?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return C(t)})(e):e,{is:$,defineProperty:z,getOwnPropertyDescriptor:k,getOwnPropertyNames:A,getOwnPropertySymbols:M,getPrototypeOf:P}=Object,L=globalThis,N=L.trustedTypes,D=N?N.emptyScript:"",I=L.reactiveElementPolyfillSupport,H=(e,t)=>e,T={toAttribute(e,t){switch(t){case Boolean:e=e?D:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},R=(e,t)=>!$(e,t),F={attribute:!0,type:String,converter:T,reflect:!1,useDefault:!1,hasChanged:R}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;let O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=F){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&z(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=k(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??F}static _$Ei(){if(this.hasOwnProperty(T("elementProperties")))return;const e=M(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(T("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(T("properties"))){const e=this.properties,t=[...A(e),...P(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(E(e))}else void 0!==e&&t.push(E(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(y)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=b.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:H).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:H;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??R)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[T("elementProperties")]=new Map,O[T("finalized")]=new Map,I?.({ReactiveElement:O}),(L.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),L.litPropertyMetadata??=new WeakMap;let O=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=F){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&z(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=k(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??F}static _$Ei(){if(this.hasOwnProperty(H("elementProperties")))return;const e=P(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(H("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(H("properties"))){const e=this.properties,t=[...A(e),...M(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(E(e))}else void 0!==e&&t.push(E(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(y)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=b.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:T).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:T;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??R)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[H("elementProperties")]=new Map,O[H("finalized")]=new Map,I?.({ReactiveElement:O}),(L.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC @@ -26,7 +26,7 @@ const j=globalThis,q=e=>e,U=j.trustedTypes,W=U?U.createPolicy("lit-html",{create * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:R},ke=(e=ze,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; +const ze={attribute:!0,type:String,converter:T,reflect:!1,hasChanged:R},ke=(e=ze,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; /** * @license * Copyright 2017 Google LLC @@ -36,7 +36,7 @@ const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:R},ke=(e=ze * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Pe(e){return Ae({...e,state:!0,attribute:!1})}const Me={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Me[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Ie(e){return De.unit(e)}function Te(e){return(e<0?"-":"")+De.format(e)}function He(e){return(Math.abs(e)/1e3).toFixed(1)}function Re(e){return Math.ceil(e/2)}function Fe(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Re(t)===Re(i)?"row-span":Fe(t)===Fe(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${Te(_)}${Ie(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?m:"#555",M=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${M}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=He(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=He(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=He(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=He(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${Te(_)}${Ie(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${Te(n)} ${Ie(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${Te(h)}${Ie(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${Te(n)}${Ie(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Mt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}const It=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);class Tt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await async function(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i):await async function(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("button");r.type="button",r.className=i?"fav-heart active":"fav-heart",r.dataset.role="favorite-heart",r.title=n("sidepanel.save_to_favorites");const c=document.createElement("ha-icon");c.setAttribute("icon",i?"mdi:heart":"mdi:heart-outline"),r.appendChild(c),r.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(r,c,t).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of It){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Tt)}catch{}const Ht=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let Rt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re` + */function Me(e){return Ae({...e,state:!0,attribute:!1})}const Pe={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Pe[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Ie(e){return De.unit(e)}function He(e){return(e<0?"-":"")+De.format(e)}function Te(e){return(Math.abs(e)/1e3).toFixed(1)}function Re(e){return Math.ceil(e/2)}function Fe(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Re(t)===Re(i)?"row-span":Fe(t)===Fe(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${He(_)}${Ie(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),M=A?m:"#555",P=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${P}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=Te(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=Te(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=Te(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=Te(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${He(_)}${Ie(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{this._favRefs?await this._buildFavoritesHorizonMaps():(await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings))}catch{}}async _buildFavoritesHorizonMaps(){if(!this._hass||!this._favRefs||!this._topology)return;const e=new Set;for(const t of Object.values(this._favRefs))t.configEntryId&&e.add(t.configEntryId);const t=new Map;await Promise.all(Array.from(e).map(async e=>{t.set(e,await this._fetchGraphSettingsFresh(e))})),this.horizonMap.clear(),this.subDeviceHorizonMap.clear();for(const e of Object.keys(this._topology.circuits)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.horizonMap.set(e,vt(n,s))}if(this._topology.sub_devices)for(const e of Object.keys(this._topology.sub_devices)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.subDeviceHorizonMap.set(e,bt(n,s))}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${He(n)} ${Ie(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this._favRefs?await this._buildFavoritesHorizonMaps():(this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${He(h)}${Ie(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${He(n)}${Ie(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Mt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Pt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}const It=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);class Ht extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);return i?this._buildHeartButton(i,t):null}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);return i?this._buildHeartButton(i,t):(console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"),null)}_buildHeartButton(e,t){const i=document.createElement("button");i.type="button",i.className=t?"fav-heart active":"fav-heart",i.dataset.role="fav-heart",i.title=n("sidepanel.save_to_favorites"),i.setAttribute("role","switch"),i.setAttribute("aria-pressed",String(t)),i.setAttribute("aria-label",n("sidepanel.save_to_favorites"));const s=document.createElement("ha-icon");return s.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),i.appendChild(s),i.addEventListener("click",t=>{t.stopPropagation(),this._toggleFavoriteEntity(i,s,e).catch(()=>{})}),i}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(o));try{o?await async function(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i):await async function(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(s));const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites"),o.appendChild(a),o.appendChild(this._buildHeartButton(t,i)),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of It){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ht)}catch{}const Tt=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let Rt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re`
${Le(n("card.loading"))}
- `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Pt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Mt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Pt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Mt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Pt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Re(Math.max(...i));0===Fe(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${Te(u)} ${Ie(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Ht.map(e=>re` + `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Mt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Pt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Mt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Pt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Mt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Re(Math.max(...i));0===Fe(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${He(u)} ${Ie(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Tt.map(e=>re`
${e.name} @@ -78,4 +78,4 @@ const ze={attribute:!0,type:String,converter:H,reflect:!1,hasChanged:R},ke=(e=ze
${n("card.no_device")}
- `}};Rt.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],Rt.prototype,"hass",void 0),v([Pe()],Rt.prototype,"_config",void 0),v([Pe()],Rt.prototype,"_discovered",void 0),v([Pe()],Rt.prototype,"_discovering",void 0),v([Pe()],Rt.prototype,"_discoveryError",void 0),v([Pe()],Rt.prototype,"_topology",void 0),v([Pe()],Rt.prototype,"_activeTab",void 0),Rt=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],Rt);class Ft extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",Ft)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); + `}};Rt.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],Rt.prototype,"hass",void 0),v([Me()],Rt.prototype,"_config",void 0),v([Me()],Rt.prototype,"_discovered",void 0),v([Me()],Rt.prototype,"_discovering",void 0),v([Me()],Rt.prototype,"_discoveryError",void 0),v([Me()],Rt.prototype,"_topology",void 0),v([Me()],Rt.prototype,"_activeTab",void 0),Rt=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],Rt);class Ft extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",Ft)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); diff --git a/dist/span-panel.js b/dist/span-panel.js index 7086a08..f3d34af 100644 --- a/dist/span-panel.js +++ b/dist/span-panel.js @@ -1,37 +1,37 @@ -let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 circuit across {panels} panels","panel.favorites_summary_many":"{circuits} circuits across {panels} panels","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito en {panels} paneles","panel.favorites_summary_many":"{circuits} circuitos en {panels} paneles","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 circuit sur {panels} panneaux","panel.favorites_summary_many":"{circuits} circuits sur {panels} panneaux","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"{panels} パネルにわたる 1 回路","panel.favorites_summary_many":"{panels} パネルにわたる {circuits} 回路","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 circuito em {panels} painéis","panel.favorites_summary_many":"{circuits} circuitos em {panels} painéis","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){return t[e]?.[n]??t.en?.[n]??n}const i="power",s="5m",o={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},a="span_panel",r="CLOSED",l="pv",c="bess",d="evse",h="sub_",p=500,u={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},g={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:u.power},_={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},f="#ff9800";function v(e,t,n,i){var s,o=arguments.length,a=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,i);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,n,a):s(t,n))||a);return o>3&&a&&Object.defineProperty(t,n,a),a}"function"==typeof SuppressedError&&SuppressedError; +let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 favorite","panel.favorites_summary_many":"{circuits} favorites","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 favori","panel.favorites_summary_many":"{circuits} favoris","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"お気に入り 1 件","panel.favorites_summary_many":"お気に入り {circuits} 件","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function i(i){return t[e]?.[i]??t.en?.[i]??i}const n="power",s="5m",o={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},a="span_panel",r="CLOSED",l="pv",c="bess",d="evse",h="sub_",p=500,u={power:{entityRole:"power",label:()=>i("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>i("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},g={soc:{entityRole:"soc",label:()=>i("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>i("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:u.power},_={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>i("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>i("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>i("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>i("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>i("shedding.unknown")}},f="#ff9800";function v(e,t,i,n){var s,o=arguments.length,a=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,n);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,i,a):s(t,i))||a);return o>3&&a&&Object.defineProperty(t,i,a),a}"function"==typeof SuppressedError&&SuppressedError; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const m=globalThis,b=m.ShadowRoot&&(void 0===m.ShadyCSS||m.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,y=Symbol(),w=new WeakMap;let x=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==y)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(b&&void 0===e){const n=void 0!==t&&1===t.length;n&&(e=w.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&w.set(t,e))}return e}toString(){return this.cssText}};const $=b?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const n of e.cssRules)t+=n.cssText;return(e=>new x("string"==typeof e?e:e+"",void 0,y))(t)})(e):e,{is:S,defineProperty:C,getOwnPropertyDescriptor:E,getOwnPropertyNames:k,getOwnPropertySymbols:z,getPrototypeOf:A}=Object,P=globalThis,M=P.trustedTypes,T=M?M.emptyScript:"",I=P.reactiveElementPolyfillSupport,N=(e,t)=>e,D={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=null!==e;break;case Number:n=null===e?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch(e){n=null}}return n}},L=(e,t)=>!S(e,t),F={attribute:!0,type:String,converter:D,reflect:!1,useDefault:!1,hasChanged:L}; +const m=globalThis,b=m.ShadowRoot&&(void 0===m.ShadyCSS||m.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,y=Symbol(),w=new WeakMap;let x=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==y)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(b&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=w.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&w.set(t,e))}return e}toString(){return this.cssText}};const $=b?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new x("string"==typeof e?e:e+"",void 0,y))(t)})(e):e,{is:S,defineProperty:C,getOwnPropertyDescriptor:E,getOwnPropertyNames:k,getOwnPropertySymbols:z,getPrototypeOf:A}=Object,P=globalThis,M=P.trustedTypes,T=M?M.emptyScript:"",I=P.reactiveElementPolyfillSupport,D=(e,t)=>e,N={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},L=(e,t)=>!S(e,t),H={attribute:!0,type:String,converter:N,reflect:!1,useDefault:!1,hasChanged:L}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),P.litPropertyMetadata??=new WeakMap;let H=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=F){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(e,n,t);void 0!==i&&C(this.prototype,e,i)}}static getPropertyDescriptor(e,t,n){const{get:i,set:s}=E(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:i,set(t){const o=i?.call(this);s?.call(this,t),this.requestUpdate(e,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??F}static _$Ei(){if(this.hasOwnProperty(N("elementProperties")))return;const e=A(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(N("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(N("properties"))){const e=this.properties,t=[...k(e),...z(e)];for(const n of t)this.createProperty(n,e[n])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const n=this._$Eu(e,t);void 0!==n&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const n=new Set(e.flat(1/0).reverse());for(const e of n)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const n=t.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(b)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const n of t){const t=document.createElement("style"),i=m.litNonce;void 0!==i&&t.setAttribute("nonce",i),t.textContent=n.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){const n=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,n);if(void 0!==i&&!0===n.reflect){const s=(void 0!==n.converter?.toAttribute?n.converter:D).toAttribute(t,n.type);this._$Em=e,null==s?this.removeAttribute(i):this.setAttribute(i,s),this._$Em=null}}_$AK(e,t){const n=this.constructor,i=n._$Eh.get(e);if(void 0!==i&&this._$Em!==i){const e=n.getPropertyOptions(i),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:D;this._$Em=i;const o=s.fromAttribute(t,e.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(e,t,n,i=!1,s){if(void 0!==e){const o=this.constructor;if(!1===i&&(s=this[e]),n??=o.getPropertyOptions(e),!((n.hasChanged??L)(s,t)||n.useDefault&&n.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:i,wrapped:s},o){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===i&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,n]of e){const{wrapped:e}=n,i=this[t];!0!==e||this._$AL.has(t)||void 0===i||this.C(t,void 0,n,i)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};H.elementStyles=[],H.shadowRootOptions={mode:"open"},H[N("elementProperties")]=new Map,H[N("finalized")]=new Map,I?.({ReactiveElement:H}),(P.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),P.litPropertyMetadata??=new WeakMap;let F=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=H){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&C(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=E(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??H}static _$Ei(){if(this.hasOwnProperty(D("elementProperties")))return;const e=A(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(D("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(D("properties"))){const e=this.properties,t=[...k(e),...z(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(b)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=m.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:N).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:N;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??L)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};F.elementStyles=[],F.shadowRootOptions={mode:"open"},F[D("elementProperties")]=new Map,F[D("finalized")]=new Map,I?.({ReactiveElement:F}),(P.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const R=globalThis,O=e=>e,q=R.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ne=/'/g,ie=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ie:ne):a===ie||a===ne?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?n+W:c>=0?(i.push(r),n.slice(0,c)+U+n.slice(c)+G+h):n+G+(-2===c?t:h)}return[de(e,o+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class pe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,n),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=ce.nextNode())&&r.length0){i.textContent=q?q.emptyScript:"";for(let n=0;nX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=pe.createElement(de(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ge(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new _e(this.O(Q()),this.O(Q()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=re}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const i=e;let a,r;for(e=s[0],a=0;ae,q=R.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ie=/'/g,ne=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...i)=>({_$litType$:e,strings:t,values:i}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const i=e.length-1,n=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ne:ie):a===ne||a===ie?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?i+W:c>=0?(n.push(r),i.slice(0,c)+U+i.slice(c)+G+h):i+G+(-2===c?t:h)}return[de(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class pe{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,i),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=ce.nextNode())&&r.length0){n.textContent=q?q.emptyScript:"";for(let i=0;iX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=pe.createElement(de(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new ge(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const s of e)n===t.length?t.push(i=new _e(this.O(Q()),this.O(Q()),this,this.options)):i=t[n],i._$AI(s),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=re}_$AI(e,t=this,i,n){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const n=e;let a,r;for(e=s[0],a=0;a{const i=n?.renderBefore??t;let s=i._$litPart$;if(void 0===s){const e=n?.renderBefore??null;i._$litPart$=s=new _e(t.insertBefore(Q(),e),e,void 0,n??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ae}};$e._$litElement$=!0,$e.finalized=!0,xe.litElementHydrateSupport?.({LitElement:$e});const Se=xe.litElementPolyfillSupport;Se?.({LitElement:$e}),(xe.litElementVersions??=[]).push("4.2.2"); + */let $e=class extends F{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((e,t,i)=>{const n=i?.renderBefore??t;let s=n._$litPart$;if(void 0===s){const e=i?.renderBefore??null;n._$litPart$=s=new _e(t.insertBefore(Q(),e),e,void 0,i??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ae}};$e._$litElement$=!0,$e.finalized=!0,xe.litElementHydrateSupport?.({LitElement:$e});const Se=xe.litElementPolyfillSupport;Se?.({LitElement:$e}),(xe.litElementVersions??=[]).push("4.2.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce,t,n)=>{const{kind:i,metadata:s}=n;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===i&&((e=Object.create(e)).wrapped=!0),o.set(n.name,e),"accessor"===i){const{name:i}=n;return{set(n){const s=t.get.call(this);t.set.call(this,n),this.requestUpdate(i,s,e,!0,n)},init(t){return void 0!==t&&this.C(i,void 0,e,t),t}}}if("setter"===i){const{name:i}=n;return function(n){const s=this[i];t.call(this,n),this.requestUpdate(i,s,e,!0,n)}}throw Error("Unsupported decorator location: "+i)}; +const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function ke(e){return(t,n)=>"object"==typeof n?Ee(e,t,n):((e,t,n)=>{const i=t.hasOwnProperty(n);return t.constructor.createProperty(n,e),i?Object.getOwnPropertyDescriptor(t,n):void 0})(e,t,n)} + */function ke(e){return(t,i)=>"object"==typeof i?Ee(e,t,i):((e,t,i)=>{const n=t.hasOwnProperty(i);return t.constructor.createProperty(i,e),n?Object.getOwnPropertyDescriptor(t,i):void 0})(e,t,i)} /** * @license * Copyright 2017 Google LLC @@ -41,12 +41,12 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */const Ae=2;class Pe{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,n){this._$Ct=e,this._$AM=t,this._$Ci=n}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}} + */const Ae=2;class Pe{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}} /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function Ne(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const De="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}class Fe{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function He(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const Re=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);class Oe extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${Ne(String(t.breaker_rating_a))}A · ${Ne(String(t.voltage))}V · Tabs [${Ne(String(t.tabs))}]`,i=this._createHeader(Ne(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);if(!i)return null;const s=document.createElement("button");s.type="button",s.className=t?"fav-heart active":"fav-heart",s.dataset.role="fav-heart",s.title=n("sidepanel.save_to_favorites");const o=document.createElement("ha-icon");return o.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),s.appendChild(o),s.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(s,o,i).catch(()=>{})}),s}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline");try{o?await async function(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}(this._hass,i):await async function(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(De)),n?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline");const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const n=this._favoriteEntityId(t.entities);n&&this._appendFavoriteHeartSection(e,n,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites");const r=document.createElement("button");r.type="button",r.className=i?"fav-heart active":"fav-heart",r.dataset.role="favorite-heart",r.title=n("sidepanel.save_to_favorites");const l=document.createElement("ha-icon");l.setAttribute("icon",i?"mdi:heart":"mdi:heart-outline"),r.appendChild(l),r.addEventListener("click",e=>{e.stopPropagation(),this._toggleFavoriteEntity(r,l,t).catch(()=>{})}),o.appendChild(a),o.appendChild(r),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const n=this._createHeader(Ne(t.name),Ne(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const n=this._subDeviceFavoriteEntityId(t.entities);n&&this._appendFavoriteHeartSection(e,n,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=Ne(e),o=Ne(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of Re){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Oe)}catch{}async function qe(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function je(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await qe(e,i),{topology:i,panelDevice:r,panelSize:s}}function Ue(e,t,i={}){const s=Ne(e.device_name||n("header.default_name")),o=Ne(e.serial||""),a=Ne(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Ge=u.power;function Ve(e){return Ge.unit(e)}function We(e){return(e<0?"-":"")+Ge.format(e)}function Be(e){return(Math.abs(e)/1e3).toFixed(1)}function Qe(e){return Math.ceil(e/2)}function Je(e){return e%2==0?1:0}function Xe(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Qe(t)===Qe(n)?"row-span":Je(t)===Je(n)?"col-span":"row-span"}function Ke(e){const t=e.chart_metric??i;return u[t]??u[i]}function Ze(e,t){const n=function(e){return Ke(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class Ye{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function et(e,t){return e?.circuits?e.circuits[t]??null:null}function tt(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function nt(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=Ne(t.name||n("grid.unknown")),C=Ke(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${We(v)}${Ve(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function it(e,t){return`\n
\n \n
\n `}const st={names:["power","battery power"],suffixes:["_power"]},ot={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},at={names:["state of energy"],suffixes:["_soe_kwh"]},rt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function lt(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function ct(e){return lt(e,st)}function dt(e){return lt(e,ot)}function ht(e){return lt(e,at)}function pt(e){return lt(e,rt)}function ut(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=ct(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?dt(s):null,v=g?ht(s):null,m=g?pt(s):null,b=gt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=_t(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${Ne(o)}\n ${Ne(s.name||"")}\n ${a?`${We(u)} ${Ve(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function gt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Ne(l)}:\n ${Ne(d)}\n
\n `}return o}function _t(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Ne(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ft(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function vt(e){const t=o[e];return t?t.ms:o[s].ms}function mt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function bt(e){return Math.max(500,Math.floor(e/5e3))}function yt(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function wt(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function xt(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function $t(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=mt(i),l=bt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,wt(t,r,l))}}}function St(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:ct(i)};i.type===c&&(e.soc=dt(i),e.soe=ht(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function Ct(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=Ze(i,n);if(!t)continue;let o;o=s&&s.has(e)?vt(s.get(e)):ft(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of St(t)){let t;t=o&&o.has(s)?vt(o.get(s)):ft(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(xt(e,n.entityIds,n.uuidByEntity,t,i)):r.push($t(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function Et(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function kt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=ft(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Be(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Be(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Be(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Be(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=Ke(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${We(f)}${Ve(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?vt(a.get(s)):c,p=d.device_type===l;Et(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class zt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function At(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function Pt(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Mt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ye,this.graphSettingsCache=new zt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,At(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,Pt(e,t))}async fetchAndBuildHorizonMaps(){try{await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)}catch{}}async loadHistory(){await Ct(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=Ze(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=vt(i),d=mt(c),h=bt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of St(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await Ct(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(kt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=ft(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=ct(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${We(i)} ${Ve(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");Et(e,t,r,o?.has(i)?vt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Tt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class It{constructor(){this._ctrl=new Mt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await je(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${Ne(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=Ue(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Xe(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Qe(Math.max(...n));0===Je(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?et(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=nt(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=it(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=nt(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=it(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=nt(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ut(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Nt="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Dt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Lt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ft="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",Ht="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function Rt(e,t,n,i,s){return`\n ${i}\n `}class Ot{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=Ne(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=Ne(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${Ne(a)} (${Ne(e)})`:Ne(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function qt(e=""){const t=e?` value="${Ne(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function jt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=Ne(t.name||n("grid.unknown")),b=Ke(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${We(h)}${Ve(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Ut(e,t,n,i,s,o){const a=nt(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Gt(e){return`
${Ne(e)}
`}function Vt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Wt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Bt(e,t,n){return e.sort((e,i)=>{const s=Vt(e[1],t,n),o=Vt(i[1],t,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Qt(e){return e.entities?.current??e.entities?.power??""}class Jt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Bt(Object.entries(n.circuits),t,i);let r=o+qt(this._searchQuery);r+='
';for(const[e,n]of a){const o=et(s,Qt(n)),a=Wt(n,t),l=this._expandedUuids.has(e);r+=jt(e,n,t,i,o,a,l),l&&(r+=Ut(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+qt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Bt(n,t,s);d+=Gt(e);for(const[e,n]of i){const i=et(o,Qt(n)),a=Wt(n,t),r=this._expandedUuids.has(e);d+=jt(e,n,t,s,i,a,r),r&&(d+=Ut(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=Ke(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Vt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${We(i)}${Ve(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=et(this._monitoringStatus,Qt(i)),o=Wt(i,this._hass),a=Ut(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Xt(e,t){return`${e}|${t}`}class Kt{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await je(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d={},h=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;d[e]=i;const s=n.config_entries?.[0]??null;s&&h.add(s);const o=n.name_by_user??n.name??i.device_name??"",p=t[e],u=p?.circuits??[],g=p?.sub_devices??[];for(const t of u){const n=i.circuits?.[t];if(!n)continue;const l=Xt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of g){const n=i.sub_devices?.[t];if(!n)continue;const r=Xt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(h),panelTopologies:d}}}const Zt="favorites",Yt="span_panel_favorites_view_state";function en(e){try{localStorage.setItem(Yt,JSON.stringify(e))}catch{}}let tn=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new It,this._monitoringTab=new Ot,this._listDashCtrl=new Mt,this._listCtrl=new Jt(this._listDashCtrl),this._favCache=new Fe,this._favCtrl=new Kt,this._favoritesMonitoringTabs=new Map,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(De,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(De,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe` + */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function De(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const Ne="favorites-changed";async function Le(e,t,i={}){const n=await e.callWS({type:"call_service",domain:a,service:t,service_data:i,return_response:!0});return n?.response??null}class He{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Fe(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const Re=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);class Oe extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,n=this._createHeader(i("sidepanel.graph_settings"),i("sidepanel.global_defaults"));e.appendChild(n);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=i("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=i("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const n=document.createElement("div");n.className="section-label",n.textContent=i("sidepanel.circuit_scales"),e.appendChild(n);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[n,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||n,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(n)??!1);e&&s.appendChild(e)}const l=h[n]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=n;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${n}`,p,()=>{const e={circuit_id:n,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=i("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const i={circuit_id:n};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const n=document.createElement("div");n.className="section-label",n.textContent=i("sidepanel.subdevice_scales"),e.appendChild(n);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[n,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||n,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(n)??!1);e&&s.appendChild(e)}const l=m[n]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=n;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${n}`,p,()=>{const e={subdevice_id:n,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=i("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const i={subdevice_id:n};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const i=`${De(String(t.breaker_rating_a))}A · ${De(String(t.voltage))}V · Tabs [${De(String(t.tabs))}]`,n=this._createHeader(De(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);return i?this._buildHeartButton(i,t):null}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);return i?this._buildHeartButton(i,t):(console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"),null)}_buildHeartButton(e,t){const n=document.createElement("button");n.type="button",n.className=t?"fav-heart active":"fav-heart",n.dataset.role="fav-heart",n.title=i("sidepanel.save_to_favorites"),n.setAttribute("role","switch"),n.setAttribute("aria-pressed",String(t)),n.setAttribute("aria-label",i("sidepanel.save_to_favorites"));const s=document.createElement("ha-icon");return s.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),n.appendChild(s),n.addEventListener("click",t=>{t.stopPropagation(),this._toggleFavoriteEntity(n,s,e).catch(()=>{})}),n}async _toggleFavoriteEntity(e,t,n){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(o));try{o?await async function(e,t){const i=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Ne)),i?.favorites??{}}(this._hass,n):await async function(e,t){const i=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Ne)),i?.favorites??{}}(this._hass,n)}catch(n){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(s));const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(n);throw this._showError(`${i("sidepanel.favorite_failed")} ${o}`),n}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,n){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=i("sidepanel.save_to_favorites"),o.appendChild(a),o.appendChild(this._buildHeartButton(t,n)),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(De(t.name),De(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const n=document.createElement("div");n.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=i("sidepanel.graph_horizon"),n.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:i("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:n}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=n,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const n={subdevice_id:t.subDeviceId};t.configEntryId&&(n.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...n,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}n.appendChild(h),e.appendChild(n)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=De(e),o=De(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const n=document.createElement("div");n.className="section",n.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=i("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${i("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),n.appendChild(s),e.appendChild(n)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const n=document.createElement("div");n.className="section",n.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=i("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of Re){const t=_[e];if(!t)continue;const n=document.createElement("option");n.value=e,n.textContent=i(`shedding.select.${e}`)||t.label(),e===l&&(n.selected=!0),a.appendChild(n)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${i("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),n.appendChild(s),e.appendChild(n)}_renderGraphHorizonSection(e,t){const n=document.createElement("div");n.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=i("sidepanel.graph_horizon"),n.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:i("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:n}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=n,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const n={circuit_id:t.uuid};t.configEntryId&&(n.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...n,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}n.appendChild(h),e.appendChild(n)}_renderMonitoringSection(e,t){const n=document.createElement("div");n.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=i("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),n.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",n.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(i("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(i("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(i("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(i("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const n={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",n).catch(e=>this._showError(`${i("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const n="custom"===e.value&&e.checked;if(p.style.display=n?"block":"none",!n&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${i("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(n)}_createThresholdRow(e,t,n,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(n),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),n=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:n?Number(n.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${i("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,n,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(n),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),n=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:n?Number(n.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${i("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Oe)}catch{}async function qe(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function je(e,t){if(!t)throw new Error(i("card.device_not_found"));const n=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=n.panel_size??function(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}(n.circuits);if(!s)throw new Error(i("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await qe(e,n),{topology:n,panelDevice:r,panelSize:s}}function Ue(e,t,n={}){const s=De(e.device_name||i("header.default_name")),o=De(e.serial||""),a=De(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==n.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${i("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${i("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${i("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${i("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${i("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${i("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${i("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Ge=u.power;function Ve(e){return Ge.unit(e)}function We(e){return(e<0?"-":"")+Ge.format(e)}function Be(e){return(Math.abs(e)/1e3).toFixed(1)}function Qe(e){return Math.ceil(e/2)}function Je(e){return e%2==0?1:0}function Xe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Qe(t)===Qe(i)?"row-span":Je(t)===Je(i)?"col-span":"row-span"}function Ke(e){const t=e.chart_metric??n;return u[t]??u[n]}function Ze(e,t){const i=function(e){return Ke(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ye{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function et(e,t){return e?.circuits?e.circuits[t]??null:null}function tt(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function it(e,t,n,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=De(t.name||i("grid.unknown")),C=Ke(c);let E;if("current"===C.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;E=`${C.format(n)}A`}else E=`${We(v)}${Ve(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${i(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function nt(e,t){return`\n
\n \n
\n `}const st={names:["power","battery power"],suffixes:["_power"]},ot={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},at={names:["state of energy"],suffixes:["_soe_kwh"]},rt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function lt(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function ct(e){return lt(e,st)}function dt(e){return lt(e,ot)}function ht(e){return lt(e,at)}function pt(e){return lt(e,rt)}function ut(e,t,n){const s=!1!==n.show_battery,o=!1!==n.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?i("subdevice.ev_charger"):s.type===c?i("subdevice.battery"):i("subdevice.fallback"),a=ct(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?dt(s):null,v=g?ht(s):null,m=g?pt(s):null,b=gt(s,t,n,new Set([a,f,v,m].filter(e=>null!==e))),y=_t(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${De(o)}\n ${De(s.name||"")}\n ${a?`${We(u)} ${Ve(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function gt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||i;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${De(l)}:\n ${De(d)}\n
\n `}return o}function _t(e,t,n,s,o,a){if(n){const t=[{key:`${h}${e}_soc`,title:i("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:i("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:i("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${De(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ft(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function vt(e){const t=o[e];return t?t.ms:o[s].ms}function mt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function bt(e){return Math.max(500,Math.floor(e/5e3))}function yt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function wt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function xt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function $t(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=mt(n),l=bt(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,wt(t,r,l))}}}function St(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:ct(n)};n.type===c&&(e.soc=dt(n),e.soe=ht(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${i}_${n}`,devId:i})}return t}async function Ct(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=Ze(n,i);if(!t)continue;let o;o=s&&s.has(e)?vt(s.get(e)):ft(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of St(t)){let t;t=o&&o.has(s)?vt(o.get(s)):ft(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(xt(e,i.entityIds,i.uuidByEntity,t,n)):r.push($t(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function Et(e,t,i,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,i,s,o,a=!1){i||(i=u[n]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:v,series:g}}(i,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function kt(e,t,n,s,o,a){if(!e||!n||!t)return;const c=ft(s);let d=0;for(const[,e]of Object.entries(n.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=Be(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;l.textContent=Be(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=Be(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=Be(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,n,s,d);const h=Ke(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(n.circuits)){const n=e.querySelector(`[data-uuid="${s}"]`);if(!n)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=n.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${We(f)}${Ve(f)}`;const x=n.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=i(y?"grid.on":"grid.off"))}let $;if(n.classList.toggle("circuit-off",!y),n.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;$=i?i.state:"unknown"}const S=_[$]??_.unknown,C=n.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=n.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=n.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=n.querySelector(".chart-container");if(z){const e=o.get(s)||[],i=n.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?vt(a.get(s)):c,p=d.device_type===l;Et(z,t,e,r,h,v,i,d.breaker_rating_a??void 0,p)}}}class zt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function At(e,t){if(!e)return s;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??s}function Pt(e,t){if(!e)return s;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??s}class Mt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ye,this.graphSettingsCache=new zt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,At(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,Pt(e,t))}async fetchAndBuildHorizonMaps(){try{this._favRefs?await this._buildFavoritesHorizonMaps():(await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings))}catch{}}async _buildFavoritesHorizonMaps(){if(!this._hass||!this._favRefs||!this._topology)return;const e=new Set;for(const t of Object.values(this._favRefs))t.configEntryId&&e.add(t.configEntryId);const t=new Map;await Promise.all(Array.from(e).map(async e=>{t.set(e,await this._fetchGraphSettingsFresh(e))})),this.horizonMap.clear(),this.subDeviceHorizonMap.clear();for(const e of Object.keys(this._topology.circuits)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.horizonMap.set(e,At(n,s))}if(this._topology.sub_devices)for(const e of Object.keys(this._topology.sub_devices)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.subDeviceHorizonMap.set(e,Pt(n,s))}}async loadHistory(){await Ct(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??s;if(!o[n]?.useRealtime)continue;const a=Ze(i,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=vt(n),d=mt(c),h=bt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of St(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await Ct(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(kt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ft(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const l=ct(r);if(l){const e=t.states[l],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${We(n)} ${Ve(n)}`)}const c=i.querySelectorAll("[data-chart-key]");for(const e of c){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let l=g.power;i.endsWith("_soc")?l=g.soc:i.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");Et(e,t,r,o?.has(n)?vt(o.get(n)):a,l,!1,c?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this._favRefs?await this._buildFavoritesHorizonMaps():(this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[i],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Tt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class It{constructor(){this._ctrl=new Mt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,n,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await je(t,n);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${De(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=Ue(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),n=Object.values(e.mains??{}),s=[...t,...n],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${i("status.monitoring")} · ${t.length} ${i("status.circuits")} · ${n.length} ${i("status.mains")}\n \n ${o>0?`${o} ${i(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${i(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${i(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Xe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Qe(Math.max(...i));0===Je(e)?r.add(n):l.add(n)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?et(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=it(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=nt(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=it(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=nt(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=it(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ut(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Dt="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Nt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Lt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ht="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",Ft="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function Rt(e,t,i,n,s){return`\n ${n}\n `}class Ot{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,n,s=""){let o;void 0!==n&&(this._configEntryId=n),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const i=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=i?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const n=De(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const n=De(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${i("monitoring.heading")}

\n\n
\n
\n

${i("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${i("monitoring.continuous")}\n \n
\n
\n ${i("monitoring.spike")}\n \n
\n
\n ${i("monitoring.window")}\n \n
\n
\n ${i("monitoring.cooldown")}\n \n
\n\n
\n

${i("notification.heading")}

\n\n
\n ${i("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${i("notification.no_targets")}
`:u.map(e=>{const n=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?i("notification.event_bus_target"):a?`${De(a)} (${De(e)})`:De(e);return``}).join("")}\n
\n
\n
\n\n
\n ${i("notification.priority")}\n \n \n ${"critical"===b?i("notification.hint.critical"):"time-sensitive"===b?i("notification.hint.time_sensitive"):"passive"===b?i("notification.hint.passive"):"active"===b?i("notification.hint.active"):""}\n \n
\n\n
\n ${i("notification.title_template")}\n \n
\n\n
\n ${i("notification.message_template")}\n \n
\n\n
\n ${i("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${i("notification.event_bus_help")} span_panel_current_alert\n ${i("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${i("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${i("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${i("monitoring.col.name")}${i("monitoring.col.continuous")}${i("monitoring.col.spike")}${i("monitoring.col.window")}${i("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const n=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,n),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:i("error.failed_save");o.textContent=`${i("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};n&&n.addEventListener("change",async()=>{const o=n.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,i)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:i("error.failed");a.textContent=`${i("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const n=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!n||!s)return;n.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const i=e.querySelector("#notify-target-select");i&&!i.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const n=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=n.map(e=>"event_bus"===e?i("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):i("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:n.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const n=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,i)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:i})}catch{}},p)};n&&n.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:n.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=i("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const n=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:n});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=i("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:i("error.failed");c.textContent=`${i("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,i,n){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const i of e.querySelectorAll(".mains-toggle"))i.addEventListener("change",async()=>{const n=i.dataset.entity,s=i.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:n,monitoring_enabled:s})})}catch{return void(i.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const i of e.querySelectorAll(".circuit-toggle"))i.addEventListener("change",async()=>{const n=i.dataset.entity,s=i.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:n,monitoring_enabled:s})})}catch{return void(i.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const i=new Map;for(const n of e.querySelectorAll(".threshold-input"))n.addEventListener("input",()=>{const s=`${n.dataset.entity}-${n.dataset.field}`,o=i.get(s);o&&clearTimeout(o),i.set(s,setTimeout(async()=>{const i=parseInt(n.value,10);if(!i||i<1)return;const s=n.dataset.entity,o=n.dataset.field,r=n.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:i})}),await this.render(e,t)}catch{n.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const i of e.querySelectorAll(".reset-btn"))i.addEventListener("click",async()=>{const n=i.dataset.entity;if(!n)return;const s=i.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:n}:{circuit_id:n});await t.callService(a,o,r),await this.render(e,t)})}}function qt(e=""){const t=e?` value="${De(e)}"`:"",n=e?"":"display:none;";return`\n
\n \n \n
\n `}function jt(e,t,n,s,o,a,l){const c=t.entities?.power,d=c?n.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?n.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=De(t.name||i("grid.unknown")),b=Ke(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,i=e?n.states[e]:null,s=i&&parseFloat(i.state)||0;w=`${b.format(s)}A`}else w=`${We(h)}${Ve(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Ut(e,t,i,n,s,o){const a=it(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Gt(e){return`
${De(e)}
`}function Vt(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;c=n?Math.abs(parseFloat(n.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Wt(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function Bt(e,t,i){return e.sort((e,n)=>{const s=Vt(e[1],t,i),o=Vt(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Qt(e){return e.entities?.current??e.entities?.power??""}class Jt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=Bt(Object.entries(i.circuits),t,n);let r=o+qt(this._searchQuery);r+='
';for(const[e,i]of a){const o=et(s,Qt(i)),a=Wt(i,t),l=this._expandedUuids.has(e);r+=jt(e,i,t,n,o,a,l),l&&(r+=Ut(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,n,s,o,a){this._unbindEvents(),this._hass=t,this._topology=n,this._config=s,this._monitoringStatus=o;const r=i("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(n.circuits)){const i=t.area??r,n=l.get(i);n?n.push([e,t]):l.set(i,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+qt(this._searchQuery);d+='
';for(const e of c){const i=l.get(e);if(!i)continue;const n=Bt(i,t,s);d+=Gt(e);for(const[e,i]of n){const n=et(o,Qt(i)),a=Wt(i,t),r=this._expandedUuids.has(e);d+=jt(e,i,t,s,n,a,r),r&&(d+=Ut(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=Ke(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:l,value:c}=Vt(r,t,n),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${We(n)}${Ve(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=et(this._monitoringStatus,Qt(n)),o=Wt(n,this._hass),a=Ut(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Xt(e,t){return`${e}|${t}`}class Kt{async build(e,t,i){const n=new Map;for(const e of i)n.set(e.id,e);const s=[];for(const[i,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=n.get(i);t&&s.push((async()=>{try{const n=await je(e,i);return{panelDeviceId:i,panel:t,topology:n.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",i,e),{panelDeviceId:i,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d=new Set;for(const{panelDeviceId:e,panel:i,topology:n}of o){if(!n)continue;const s=i.config_entries?.[0]??null;s&&d.add(s);const o=i.name_by_user??i.name??n.device_name??"",h=t[e],p=h?.circuits??[],u=h?.sub_devices??[];for(const t of p){const i=n.circuits?.[t];if(!i)continue;const l=Xt(e,t),d=a&&o?`${o} · ${i.name}`:i.name;r[l]={...i,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of u){const i=n.sub_devices?.[t];if(!i)continue;const r=Xt(e,t),d=a&&o&&i.name?`${o} · ${i.name}`:i.name??t;l[r]={...i,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(d)}}}const Zt="favorites",Yt="span_panel_favorites_view_state";function ei(e){try{localStorage.setItem(Yt,JSON.stringify(e))}catch{}}let ti=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new It,this._monitoringTab=new Ot,this._listDashCtrl=new Mt,this._listCtrl=new Jt(this._listDashCtrl),this._favCache=new He,this._favCtrl=new Kt,this._favoritesMonitoringTabs=new Map,this._refreshSeq=0,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ne,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ne,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const i=e.querySelector("span-side-panel");i&&(i.hass=this.hass)}}}setConfig(e){}render(){var i,n,s;return i=this.hass?.language,e=i&&t[i]?i:"en",this.hass?this._discovered?oe`
@@ -59,7 +59,7 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce
-
${Te((i=this._buildTabList(),s=this._activeTab,`
${i.map(e=>``).join("")}
`))}
+
${Te((n=this._buildTabList(),s=this._activeTab,`
${n.map(e=>``).join("")}
`))}
@@ -95,7 +95,7 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce
${"Loading…"}
- `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===Zt}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,en(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,en(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==Zt).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(Yt);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===Zt){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!He(t))return e;return[{id:Zt,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){this._favCache.invalidate();const e=await this._loadFavorites(),t=this._selectedPanelId===Zt;this._favorites=e;const n=this._panels.filter(e=>e.id!==Zt);if(this._panels=this._buildPanelList(n,e),t&&!He(e)){!function(){try{localStorage.removeItem(Yt)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return Ue(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=Object.values(this._favorites).filter(e=>(e.circuits?.length??0)>0||(e.sub_devices?.length??0)>0).length,t=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),i=n(1===t?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(t)).replace("{panels}",String(e)),s="current"===(this._chartMetric||"power");return`\n
\n
${Ne(n("panel.favorites"))}
\n
${Ne(i)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await qe(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==Zt),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ut(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const o=document.createElement("h3");o.style.margin="8px 0 12px",o.style.fontSize="1em",o.textContent=t?.name_by_user??t?.name??e,n.appendChild(o);const a=document.createElement("div");n.appendChild(a),i.appendChild(n);const r=new Ot;this._favoritesMonitoringTabs.set(e,r),await r.render(a,this.hass,e)}}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};tn.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` + `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===Zt}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const i=t.dataset.tab;i&&i!==this._activeTab&&(this._activeTab=i,this._isFavoritesView&&"dashboard"!==i&&(this._favoritesViewState.activeTab=i,ei(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const i=this._favoritesViewState;i.activeTab=t.view;const n=this._listDashCtrl.topology?.circuits??{};i.expanded[t.view]=t.expanded.filter(e=>e in n),i.searchQuery=t.searchQuery,ei(i)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==Zt).map(e=>e.id)),i=new Set(e.map(e=>e.id));if((t.size!==i.size||[...t].some(e=>!i.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(Yt);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const i=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(i.activity)?i.activity:[],area:Array.isArray(i.area)?i.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===Zt){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Fe(t))return e;return[{id:Zt,name:i("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){const e=++this._refreshSeq;this._favCache.invalidate();const t=await this._loadFavorites();if(e!==this._refreshSeq)return;const i=this._selectedPanelId===Zt;this._favorites=t;const n=this._panels.filter(e=>e.id!==Zt);if(this._panels=this._buildPanelList(n,t),i&&!Fe(t)){!function(){try{localStorage.removeItem(Yt)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:i("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:i("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:i("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:i("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return Ue(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=function(e){let t=0;for(const i of Object.values(e))t+=(i.circuits?.length??0)+(i.sub_devices?.length??0);return t}(this._favorites),t=i(1===e?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(e)),n="current"===(this._chartMetric||"power");return`\n
\n
${De(i("panel.favorites"))}
\n
${De(t)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),i=this._panels.find(e=>e.id===this._selectedPanelId),n=i?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,n);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),i=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),n=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,n,this.hass,i),await this._listDashCtrl.monitoringCache.fetch(this.hass,i),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,n):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,n,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message,e.appendChild(i)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),i=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),n=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,n,this.hass,i),await this._listDashCtrl.monitoringCache.fetch(this.hass,i),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,n):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,n,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await qe(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message,e.appendChild(i)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),i=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,i??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==Zt),n=await this._favCtrl.build(this.hass,this._favorites,t),s=n.topology,o=n.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=i("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,n.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ut(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message,e.appendChild(i)}}async _renderFavoritesMonitoring(e,t,i){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const n=document.createElement("div");n.className="favorites-monitoring-stack",e.appendChild(n);const s=new Map;for(const e of i){const t=e.config_entries?.[0];t&&s.set(t,e)}const o=new Map;for(const e of t){const t=s.get(e),i=document.createElement("div");i.className="favorites-monitoring-block",i.style.marginBottom="24px";const a=document.createElement("h2");a.style.margin="8px 0 12px",a.style.fontSize="1em",a.textContent=t?.name_by_user??t?.name??e,i.appendChild(a);const r=document.createElement("div");i.appendChild(r),n.appendChild(i);const l=new Ot;o.set(e,l);try{await l.render(r,this.hass,e)}catch(t){console.warn("SPAN Panel: favorites monitoring render failed",e,t);const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message??String(t),r.appendChild(i)}}this._favoritesMonitoringTabs=o}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};ti.styles=((e,...t)=>{const i=1===e.length?e[0]:t.reduce((t,i,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[n+1],e[0]);return new x(i,e,y)})` :host { color: var(--primary-text-color); } @@ -185,4 +185,4 @@ const Ce={attribute:!0,type:String,converter:D,reflect:!1,hasChanged:L},Ee=(e=Ce opacity: 1; border-bottom-color: var(--app-header-text-color, white); } - `,v([ke({attribute:!1})],tn.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],tn.prototype,"narrow",void 0),v([ze()],tn.prototype,"_panels",void 0),v([ze()],tn.prototype,"_selectedPanelId",void 0),v([ze()],tn.prototype,"_activeTab",void 0),v([ze()],tn.prototype,"_discovered",void 0),v([ze()],tn.prototype,"_discoveryError",void 0),v([ze()],tn.prototype,"_chartMetric",void 0),v([ze()],tn.prototype,"_favorites",void 0),tn=v([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],tn),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let nn=!1;const sn=tn.prototype.connectedCallback;tn.prototype.connectedCallback=function(){nn=!0,sn.call(this)};const on=tn.prototype.disconnectedCallback;tn.prototype.disconnectedCallback=function(){nn=!1,on.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(nn||window.location.pathname.includes("span-panel")&&setTimeout(()=>{nn||location.reload()},200))}); + `,v([ke({attribute:!1})],ti.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],ti.prototype,"narrow",void 0),v([ze()],ti.prototype,"_panels",void 0),v([ze()],ti.prototype,"_selectedPanelId",void 0),v([ze()],ti.prototype,"_activeTab",void 0),v([ze()],ti.prototype,"_discovered",void 0),v([ze()],ti.prototype,"_discoveryError",void 0),v([ze()],ti.prototype,"_chartMetric",void 0),v([ze()],ti.prototype,"_favorites",void 0),ti=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],ti),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let ii=!1;const ni=ti.prototype.connectedCallback;ti.prototype.connectedCallback=function(){ii=!0,ni.call(this)};const si=ti.prototype.disconnectedCallback;ti.prototype.disconnectedCallback=function(){ii=!1,si.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(ii||window.location.pathname.includes("span-panel")&&setTimeout(()=>{ii||location.reload()},200))}); diff --git a/src/core/dashboard-controller.ts b/src/core/dashboard-controller.ts index 53e915a..b67e74c 100644 --- a/src/core/dashboard-controller.ts +++ b/src/core/dashboard-controller.ts @@ -146,13 +146,55 @@ export class DashboardController { async fetchAndBuildHorizonMaps(): Promise { try { - await this.graphSettingsCache.fetch(this._hass!, this._configEntryId); - this.buildHorizonMaps(this.graphSettingsCache.settings); + if (this._favRefs) { + await this._buildFavoritesHorizonMaps(); + } else { + await this.graphSettingsCache.fetch(this._hass!, this._configEntryId); + this.buildHorizonMaps(this.graphSettingsCache.settings); + } } catch { // Graph settings unavailable -- use defaults } } + /** + * Build horizon maps for the Favorites pseudo-panel by fetching graph + * settings per contributing config entry in parallel, then routing + * each composite circuit/sub-device id through its ``FavoriteRef`` to + * the originating entry's settings. Without this, every favorited + * target would incorrectly resolve against the primary entry's + * settings, masking per-target overrides on non-primary panels. + */ + private async _buildFavoritesHorizonMaps(): Promise { + if (!this._hass || !this._favRefs || !this._topology) return; + const entryIds = new Set(); + for (const ref of Object.values(this._favRefs)) { + if (ref.configEntryId) entryIds.add(ref.configEntryId); + } + const settingsByEntry = new Map(); + await Promise.all( + Array.from(entryIds).map(async eid => { + settingsByEntry.set(eid, await this._fetchGraphSettingsFresh(eid)); + }) + ); + this.horizonMap.clear(); + this.subDeviceHorizonMap.clear(); + for (const compositeId of Object.keys(this._topology.circuits)) { + const ref = this._favRefs[compositeId]; + const settings = ref?.configEntryId ? (settingsByEntry.get(ref.configEntryId) ?? null) : null; + const realId = ref?.targetId ?? compositeId; + this.horizonMap.set(compositeId, getEffectiveHorizon(settings, realId)); + } + if (this._topology.sub_devices) { + for (const compositeId of Object.keys(this._topology.sub_devices)) { + const ref = this._favRefs[compositeId]; + const settings = ref?.configEntryId ? (settingsByEntry.get(ref.configEntryId) ?? null) : null; + const realId = ref?.targetId ?? compositeId; + this.subDeviceHorizonMap.set(compositeId, getEffectiveSubDeviceHorizon(settings, realId)); + } + } + } + async loadHistory(): Promise { await loadHistory(this._hass!, this._topology!, this._config!, this.powerHistory, this.horizonMap, this.subDeviceHorizonMap); } @@ -265,9 +307,14 @@ export class DashboardController { async onGraphSettingsChanged(root: DOMRoot): Promise { if (!this._hass) return; - this.graphSettingsCache.invalidate(); - await this.graphSettingsCache.fetch(this._hass, this._configEntryId); - this.buildHorizonMaps(this.graphSettingsCache.settings); + if (this._favRefs) { + // Favorites view: per-entry fresh fetches, routed through refs. + await this._buildFavoritesHorizonMaps(); + } else { + this.graphSettingsCache.invalidate(); + await this.graphSettingsCache.fetch(this._hass, this._configEntryId); + this.buildHorizonMaps(this.graphSettingsCache.settings); + } this.powerHistory.clear(); try { diff --git a/src/core/favorites-controller.ts b/src/core/favorites-controller.ts index 6529c81..226be10 100644 --- a/src/core/favorites-controller.ts +++ b/src/core/favorites-controller.ts @@ -9,30 +9,10 @@ export function buildCompositeId(panelDeviceId: string, circuitUuid: string): st return `${panelDeviceId}${COMPOSITE_SEPARATOR}${circuitUuid}`; } -/** - * Parse a composite id back into its ``(panelDeviceId, circuitUuid)`` - * parts. Returns ``null`` when the input is not a composite id — callers - * should treat a plain uuid as "use the current panel" in that case. - */ -export function parseCompositeId(id: string): { panelDeviceId: string; circuitUuid: string } | null { - const idx = id.indexOf(COMPOSITE_SEPARATOR); - if (idx <= 0 || idx === id.length - 1) return null; - return { - panelDeviceId: id.slice(0, idx), - circuitUuid: id.slice(idx + 1), - }; -} - export interface FavoritesBuildResult { topology: FavoritesTopology; /** Unique contributing config entry ids (for monitoring tab stacking). */ entryIds: string[]; - /** - * Per-panel raw topologies, keyed by panel device id. Callers that - * need to resolve a composite id to a real circuit (e.g. the side - * panel's gear routing) can look up the originating topology here. - */ - panelTopologies: Record; } /** @@ -76,12 +56,10 @@ export class FavoritesController { const mergedCircuits: FavoritesTopology["circuits"] = {}; const mergedSubDevices: NonNullable = {}; const refs: Record = {}; - const panelTopologies: Record = {}; const entryIds = new Set(); for (const { panelDeviceId, panel, topology } of contributing) { if (!topology) continue; - panelTopologies[panelDeviceId] = topology; const configEntryId = panel.config_entries?.[0] ?? null; if (configEntryId) entryIds.add(configEntryId); @@ -130,7 +108,6 @@ export class FavoritesController { return { topology, entryIds: Array.from(entryIds), - panelTopologies, }; } } diff --git a/src/core/side-panel.ts b/src/core/side-panel.ts index 04e6447..d91f375 100644 --- a/src/core/side-panel.ts +++ b/src/core/side-panel.ts @@ -27,9 +27,15 @@ interface PanelModeConfig { showFavorites?: boolean; /** HA device id of the panel whose side panel is open (source of favorites). */ favoritePanelDeviceId?: string; - /** Circuit uuids already favorited for that panel — drives heart fill. */ + /** + * Circuit uuids favorited for this panel at the moment the side panel + * was opened. Snapshot — not live. Subsequent toggles update only the + * clicked heart's optimistic class via ``_toggleFavoriteEntity``; if + * the user closes and reopens the side panel, ``DashboardController.onGearClick`` + * rebuilds the config from the latest ``_panelFavorites``. + */ favoriteCircuitUuids?: Set; - /** Sub-device HA device ids already favorited — drives heart fill. */ + /** Sub-device HA device ids favorited for this panel — same snapshot semantics. */ favoriteSubDeviceIds?: Set; /** Override config entry id used for cross-panel service routing (favorites). */ configEntryId?: string | null; @@ -695,25 +701,7 @@ class SpanSidePanel extends HTMLElement { private _buildSubDeviceFavoriteHeart(entities: Record | undefined, isFavorite: boolean): HTMLButtonElement | null { const entityId = this._subDeviceFavoriteEntityId(entities); if (!entityId) return null; - - const btn = document.createElement("button"); - btn.type = "button"; - btn.className = isFavorite ? "fav-heart active" : "fav-heart"; - btn.dataset.role = "fav-heart"; - btn.title = t("sidepanel.save_to_favorites"); - - const icon = document.createElement("ha-icon"); - icon.setAttribute("icon", isFavorite ? "mdi:heart" : "mdi:heart-outline"); - btn.appendChild(icon); - - btn.addEventListener("click", (ev: Event) => { - ev.stopPropagation(); - this._toggleFavoriteEntity(btn, icon, entityId).catch(() => { - // error message shown inside _toggleFavoriteEntity - }); - }); - - return btn; + return this._buildHeartButton(entityId, isFavorite); } /** @@ -723,13 +711,29 @@ class SpanSidePanel extends HTMLElement { */ private _buildFavoriteHeart(entities: CircuitEntities | undefined, isFavorite: boolean): HTMLButtonElement | null { const entityId = this._favoriteEntityId(entities); - if (!entityId) return null; + if (!entityId) { + console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"); + return null; + } + return this._buildHeartButton(entityId, isFavorite); + } + /** + * Shared heart-button builder used by both circuit and sub-device + * panel-mode rows and by the per-target side-panel Favorite section. + * Renders an accessible toggle (``role=switch``, ``aria-pressed``, + * ``aria-label``) so screen readers announce both the action and the + * current state — ``title`` alone isn't surfaced. + */ + private _buildHeartButton(entityId: string, isFavorite: boolean): HTMLButtonElement { const btn = document.createElement("button"); btn.type = "button"; btn.className = isFavorite ? "fav-heart active" : "fav-heart"; btn.dataset.role = "fav-heart"; btn.title = t("sidepanel.save_to_favorites"); + btn.setAttribute("role", "switch"); + btn.setAttribute("aria-pressed", String(isFavorite)); + btn.setAttribute("aria-label", t("sidepanel.save_to_favorites")); const icon = document.createElement("ha-icon"); icon.setAttribute("icon", isFavorite ? "mdi:heart" : "mdi:heart-outline"); @@ -749,9 +753,10 @@ class SpanSidePanel extends HTMLElement { if (!this._hass) return; const wasActive = btn.classList.contains("active"); const nextActive = !wasActive; - // Optimistically flip; roll back on error. + // Optimistically flip class, icon, and aria-pressed; roll back on error. btn.classList.toggle("active", nextActive); icon.setAttribute("icon", nextActive ? "mdi:heart" : "mdi:heart-outline"); + btn.setAttribute("aria-pressed", String(nextActive)); try { if (nextActive) { await addFavorite(this._hass, entityId); @@ -761,6 +766,7 @@ class SpanSidePanel extends HTMLElement { } catch (err) { btn.classList.toggle("active", wasActive); icon.setAttribute("icon", wasActive ? "mdi:heart" : "mdi:heart-outline"); + btn.setAttribute("aria-pressed", String(wasActive)); const message = _extractErrorMessage(err); this._showError(`${t("sidepanel.favorite_failed")} ${message}`); throw err; @@ -791,25 +797,8 @@ class SpanSidePanel extends HTMLElement { label.className = "field-label"; label.textContent = t("sidepanel.save_to_favorites"); - const btn = document.createElement("button"); - btn.type = "button"; - btn.className = isFavorite ? "fav-heart active" : "fav-heart"; - btn.dataset.role = "favorite-heart"; - btn.title = t("sidepanel.save_to_favorites"); - - const icon = document.createElement("ha-icon"); - icon.setAttribute("icon", isFavorite ? "mdi:heart" : "mdi:heart-outline"); - btn.appendChild(icon); - - btn.addEventListener("click", (ev: Event) => { - ev.stopPropagation(); - this._toggleFavoriteEntity(btn, icon, entityId).catch(() => { - // error message shown inside _toggleFavoriteEntity - }); - }); - row.appendChild(label); - row.appendChild(btn); + row.appendChild(this._buildHeartButton(entityId, isFavorite)); section.appendChild(row); body.appendChild(section); } diff --git a/src/i18n.ts b/src/i18n.ts index be60364..9ae0be4 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -153,8 +153,8 @@ const translations: Record> = { // Favorites pseudo-panel "panel.favorites": "Favorites", - "panel.favorites_summary_one": "1 circuit across {panels} panels", - "panel.favorites_summary_many": "{circuits} circuits across {panels} panels", + "panel.favorites_summary_one": "1 favorite", + "panel.favorites_summary_many": "{circuits} favorites", // Monitoring status bar "status.monitoring": "Monitoring", @@ -326,8 +326,8 @@ const translations: Record> = { "sidepanel.save_to_favorites": "Guardar en favoritos", "sidepanel.favorite_failed": "Error al actualizar favoritos:", "panel.favorites": "Favoritos", - "panel.favorites_summary_one": "1 circuito en {panels} paneles", - "panel.favorites_summary_many": "{circuits} circuitos en {panels} paneles", + "panel.favorites_summary_one": "1 favorito", + "panel.favorites_summary_many": "{circuits} favoritos", "status.monitoring": "Monitoreo", "status.circuits": "circuitos", "status.mains": "alimentaci\u00f3n", @@ -491,8 +491,8 @@ const translations: Record> = { "sidepanel.save_to_favorites": "Enregistrer dans les favoris", "sidepanel.favorite_failed": "\u00c9chec de la mise \u00e0 jour du favori :", "panel.favorites": "Favoris", - "panel.favorites_summary_one": "1 circuit sur {panels} panneaux", - "panel.favorites_summary_many": "{circuits} circuits sur {panels} panneaux", + "panel.favorites_summary_one": "1 favori", + "panel.favorites_summary_many": "{circuits} favoris", "status.monitoring": "Surveillance", "status.circuits": "circuits", "status.mains": "alimentation", @@ -658,8 +658,8 @@ const translations: Record> = { "sidepanel.save_to_favorites": "\u304a\u6c17\u306b\u5165\u308a\u306b\u4fdd\u5b58", "sidepanel.favorite_failed": "\u304a\u6c17\u306b\u5165\u308a\u306e\u66f4\u65b0\u306b\u5931\u6557:", "panel.favorites": "\u304a\u6c17\u306b\u5165\u308a", - "panel.favorites_summary_one": "{panels} \u30d1\u30cd\u30eb\u306b\u308f\u305f\u308b 1 \u56de\u8def", - "panel.favorites_summary_many": "{panels} \u30d1\u30cd\u30eb\u306b\u308f\u305f\u308b {circuits} \u56de\u8def", + "panel.favorites_summary_one": "\u304a\u6c17\u306b\u5165\u308a 1 \u4ef6", + "panel.favorites_summary_many": "\u304a\u6c17\u306b\u5165\u308a {circuits} \u4ef6", "status.monitoring": "\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0", "status.circuits": "\u56de\u8def", "status.mains": "\u4e3b\u96fb\u6e90", @@ -827,8 +827,8 @@ const translations: Record> = { "sidepanel.save_to_favorites": "Salvar nos favoritos", "sidepanel.favorite_failed": "Falha ao atualizar favorito:", "panel.favorites": "Favoritos", - "panel.favorites_summary_one": "1 circuito em {panels} painéis", - "panel.favorites_summary_many": "{circuits} circuitos em {panels} painéis", + "panel.favorites_summary_one": "1 favorito", + "panel.favorites_summary_many": "{circuits} favoritos", "status.monitoring": "Monitoramento", "status.circuits": "circuitos", "status.mains": "alimenta\u00e7\u00e3o", diff --git a/src/panel/span-panel.ts b/src/panel/span-panel.ts index 694771f..d073524 100644 --- a/src/panel/span-panel.ts +++ b/src/panel/span-panel.ts @@ -99,6 +99,14 @@ export class SpanPanelElement extends LitElement { * Monitoring tab — one block per contributing panel's config entry. */ private _favoritesMonitoringTabs: Map = new Map(); + /** + * Monotonic token incremented on each ``_refreshFavorites`` call. + * Concurrent invocations (rapid heart toggles → multiple + * ``favorites-changed`` events) compare their token against the latest + * after each await; superseded callbacks bail out without touching + * state or scheduling another tab render. + */ + private _refreshSeq = 0; private _areaUnsub: (() => void) | null = null; private _onVisibilityChange: (() => void) | null = null; private _onFavoritesChanged: (() => void) | null = null; @@ -582,8 +590,12 @@ export class SpanPanelElement extends LitElement { * multiple targets in a row. */ private async _refreshFavorites(): Promise { + const myToken = ++this._refreshSeq; this._favCache.invalidate(); const favorites = await this._loadFavorites(); + // Bail out if a newer refresh has superseded us — its reload + render + // will land with the latest data; don't double-render or fight it. + if (myToken !== this._refreshSeq) return; const wasOnFavorites = this._selectedPanelId === FAVORITES_PANEL_ID; this._favorites = favorites; @@ -649,11 +661,12 @@ export class SpanPanelElement extends LitElement { * no longer renders its own — the persistent header owns it). */ private _buildFavoritesSummaryHTML(): string { - const panelCount = Object.values(this._favorites).filter(e => (e.circuits?.length ?? 0) > 0 || (e.sub_devices?.length ?? 0) > 0).length; const circuitCount = countFavorites(this._favorites); - const key = circuitCount === 1 ? "panel.favorites_summary_one" : "panel.favorites_summary_many"; - const template = t(key); - const summary = template.replace("{circuits}", String(circuitCount)).replace("{panels}", String(panelCount)); + // Explicit conditional so the i18n validator can statically detect + // both keys; dynamic ``t(`panel.favorites_summary_${...}`)`` would + // be flagged as unused. + const template = circuitCount === 1 ? t("panel.favorites_summary_one") : t("panel.favorites_summary_many"); + const summary = template.replace("{circuits}", String(circuitCount)); const isAmpsMode = (this._chartMetric || "power") === "current"; return `
@@ -870,13 +883,17 @@ export class SpanPanelElement extends LitElement { if (eid) panelsByEntry.set(eid, panel); } + // Build into a local map and only assign to the instance field after + // every render attempts so a single failure can't orphan tabs that + // _renderTab's cleanup loop never sees. + const tabs = new Map(); for (const entryId of entryIds) { const panel = panelsByEntry.get(entryId); const block = document.createElement("div"); block.className = "favorites-monitoring-block"; block.style.marginBottom = "24px"; - const heading = document.createElement("h3"); + const heading = document.createElement("h2"); heading.style.margin = "8px 0 12px"; heading.style.fontSize = "1em"; heading.textContent = panel?.name_by_user ?? panel?.name ?? entryId; @@ -887,9 +904,18 @@ export class SpanPanelElement extends LitElement { wrapper.appendChild(block); const tab = new MonitoringTab(); - this._favoritesMonitoringTabs.set(entryId, tab); - await tab.render(body, this.hass, entryId); + tabs.set(entryId, tab); + try { + await tab.render(body, this.hass, entryId); + } catch (err) { + console.warn("SPAN Panel: favorites monitoring render failed", entryId, err); + const errEl = document.createElement("p"); + errEl.style.color = "var(--error-color)"; + errEl.textContent = (err as Error).message ?? String(err); + body.appendChild(errEl); + } } + this._favoritesMonitoringTabs = tabs; } /** From 294a3b28d9be5d80540fc8888a57b002aade5c3b Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:26:18 -0700 Subject: [PATCH 06/97] fix: re-sort list view rows on hass updates updateCollapsedRows refreshed each row's power/current in place but never re-evaluated sort order, so 'By Activity' (and within-area sort) froze to the initial render order. Partition .list-view into groups bounded by .area-header and reorder rows (keeping expanded-content siblings glued to their parents) after updating values. --- dist/span-panel-card.js | 6 +-- dist/span-panel.js | 24 ++++----- src/core/list-view-controller.ts | 90 +++++++++++++++++++++++++++++--- 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/dist/span-panel-card.js b/dist/span-panel-card.js index d6d9d19..c96d3fa 100644 --- a/dist/span-panel-card.js +++ b/dist/span-panel-card.js @@ -36,7 +36,7 @@ const ze={attribute:!0,type:String,converter:T,reflect:!1,hasChanged:R},ke=(e=ze * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function Me(e){return Ae({...e,state:!0,attribute:!1})}const Pe={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Pe[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Ie(e){return De.unit(e)}function He(e){return(e<0?"-":"")+De.format(e)}function Te(e){return(Math.abs(e)/1e3).toFixed(1)}function Re(e){return Math.ceil(e/2)}function Fe(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Re(t)===Re(i)?"row-span":Fe(t)===Fe(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${He(_)}${Ie(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),M=A?m:"#555",P=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${P}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=Te(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=Te(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=Te(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=Te(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${He(_)}${Ie(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{this._favRefs?await this._buildFavoritesHorizonMaps():(await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings))}catch{}}async _buildFavoritesHorizonMaps(){if(!this._hass||!this._favRefs||!this._topology)return;const e=new Set;for(const t of Object.values(this._favRefs))t.configEntryId&&e.add(t.configEntryId);const t=new Map;await Promise.all(Array.from(e).map(async e=>{t.set(e,await this._fetchGraphSettingsFresh(e))})),this.horizonMap.clear(),this.subDeviceHorizonMap.clear();for(const e of Object.keys(this._topology.circuits)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.horizonMap.set(e,vt(n,s))}if(this._topology.sub_devices)for(const e of Object.keys(this._topology.sub_devices)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.subDeviceHorizonMap.set(e,bt(n,s))}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${He(n)} ${Ie(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this._favRefs?await this._buildFavoritesHorizonMaps():(this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${He(h)}${Ie(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i){return e.sort((e,n)=>{const s=Et(e[1],t,i),o=Et(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function kt(e){return e.entities?.current??e.entities?.power??""}class At{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=zt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,kt(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=zt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,kt(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${He(n)}${Ie(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,kt(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Mt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Pt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Lt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Nt="favorites-changed";async function Dt(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}const It=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);class Ht extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);return i?this._buildHeartButton(i,t):null}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);return i?this._buildHeartButton(i,t):(console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"),null)}_buildHeartButton(e,t){const i=document.createElement("button");i.type="button",i.className=t?"fav-heart active":"fav-heart",i.dataset.role="fav-heart",i.title=n("sidepanel.save_to_favorites"),i.setAttribute("role","switch"),i.setAttribute("aria-pressed",String(t)),i.setAttribute("aria-label",n("sidepanel.save_to_favorites"));const s=document.createElement("ha-icon");return s.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),i.appendChild(s),i.addEventListener("click",t=>{t.stopPropagation(),this._toggleFavoriteEntity(i,s,e).catch(()=>{})}),i}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(o));try{o?await async function(e,t){const i=await Dt(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i):await async function(e,t){const i=await Dt(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Nt)),i?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(s));const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites"),o.appendChild(a),o.appendChild(this._buildHeartButton(t,i)),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of It){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Ht)}catch{}const Tt=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let Rt=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new At(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re` + */function Me(e){return Ae({...e,state:!0,attribute:!1})}const Pe={"&":"&","<":"<",">":">",'"':""","'":"'"};function Le(e){return String(e).replace(/[&<>"']/g,e=>Pe[e]??e)}function Ne(e,t,i={}){const s=Le(e.device_name||n("header.default_name")),o=Le(e.serial||""),a=Le(e.firmware||""),r="current"===(t.chart_metric||"power"),c=!1!==i.showSwitches,l=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${c?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${l?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(f).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const De=g.power;function Ie(e){return De.unit(e)}function He(e){return(e<0?"-":"")+De.format(e)}function Te(e){return(Math.abs(e)/1e3).toFixed(1)}function Re(e){return Math.ceil(e/2)}function Fe(e){return e%2==0?1:0}function Oe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Re(t)===Re(i)?"row-span":Fe(t)===Fe(i)?"col-span":"row-span"}function je(e){const t=e.chart_metric??s;return g[t]??g[s]}function qe(e,t){const i=function(e){return je(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ue{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function We(e,t){return e?.circuits?e.circuits[t]??null:null}function Ge(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function Be(e,t,i,s,o,a,r,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,_=g&&parseFloat(g.state)||0,v=t.device_type===l||_<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===c,x=t.breaker_rating_a,S=x?`${Math.round(x)}A`:"",C=Le(t.name||n("grid.unknown")),E=je(r);let $;if("current"===E.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;$=`${E.format(n)}A`}else $=`${He(_)}${Ie(_)}`;const z=h||"unknown";let k="";if("unknown"!==z){const e=f[z]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};k=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),M=A?m:"#555",P=``;let L="";if(null!=d?.utilization_pct){const e=d.utilization_pct;L=`${Math.round(e)}%`}const N=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${S?`${S}`:""}\n ${C}\n
\n
\n \n ${$}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${k}\n ${L}\n ${P}\n
\n
\n
\n `}function Ve(e,t){return`\n
\n \n
\n `}const Qe={names:["power","battery power"],suffixes:["_power"]},Je={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},Xe={names:["state of energy"],suffixes:["_soe_kwh"]},Ke={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function Ze(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function Ye(e){return Ze(e,Qe)}function et(e){return Ze(e,Je)}function tt(e){return Ze(e,Xe)}function it(e){return Ze(e,Ke)}function nt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let c=a.original_name||r.attributes.friendly_name||i;const l=e.name||"";let d;if(c.startsWith(l+" ")&&(c=c.slice(l.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${Le(c)}:\n ${Le(d)}\n
\n `}return o}function st(e,t,i,s,o,a){if(i){const t=[{key:`${p}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${p}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${p}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${Le(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ot(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function at(e){const t=a[e];return t?t.ms:a[o].ms}function rt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function ct(e){return Math.max(500,Math.floor(e/5e3))}function lt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function dt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function ht(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function pt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=rt(n),c=ct(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,dt(t,r,c))}}}function ut(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:Ye(n)};n.type===d&&(e.soc=et(n),e.soe=tt(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${p}${i}_${n}`,devId:i})}return t}async function gt(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=qe(n,i);if(!t)continue;let o;o=s&&s.has(e)?at(s.get(e)):ot(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of ut(t)){let t;t=o&&o.has(s)?at(o.get(s)):ot(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(ht(e,i.entityIds,i.uuidByEntity,t,n)):r.push(pt(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function _t(e,t,i,n,o,a,r,c,l){const{options:d,series:h}=function(e,t,i,n,o,a=!1){i||(i=g[s]);const r=n?"140, 160, 220":"77, 217, 175",c=`rgb(${r})`,l=Date.now(),d=l-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),u=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:c},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:c}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),u.push({type:"line",data:[[d,.8*o],[l,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),u.push({type:"line",data:[[d,o],[l,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const m={xAxis:{type:"time",min:d,max:l,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:m,series:u}}(i,n,o,a,c,l),p=r??120;e.style.minHeight=p+"px";let u=e.querySelector("ha-chart-base");u||(u=document.createElement("ha-chart-base"),u.style.display="block",u.style.width="100%",u.hass=t,e.innerHTML="",e.appendChild(u));const _=e.clientHeight;u.height=(_>0?_:p)+"px",u.hass=t,u.options=d,u.data=h}function ft(e,t,i,s,o,a){if(!e||!i||!t)return;const r=ot(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=Te(s)),r&&(r.textContent="kW")}const c=e.querySelector(".stat-upstream .stat-value"),l=e.querySelector(".stat-upstream .stat-unit");if(c){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;c.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",l&&(l.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;c.textContent=Te(e),l&&(l.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=Te(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=Te(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,i,s,d);const h=je(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,_=g&&parseFloat(g.state)||0,m=d.device_type===l||_<0,v=d.entities?.switch,b=v?t.states[v]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===c,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${He(_)}${Ie(_)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let S;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",m),d.always_on)S="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;S=i?i.state:"unknown"}const C=f[S]??f.unknown,E=i.querySelector(".shedding-icon");E&&(E.setAttribute("icon",C.icon),E.style.color=C.color,E.title=C.label());const $=i.querySelector(".shedding-icon-secondary");$&&(C.icon2?($.setAttribute("icon",C.icon2),$.style.color=C.color,$.style.display=""):$.style.display="none");const z=i.querySelector(".shedding-label");z&&(C.textLabel?(z.textContent=C.textLabel,z.style.color=C.color,z.style.display=""):z.style.display="none");const k=i.querySelector(".chart-container");if(k){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,c=a?.has(s)?at(a.get(s)):r,p=d.device_type===l;_t(k,t,e,c,h,m,n,d.breaker_rating_a??void 0,p)}}}class mt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function vt(e,t){if(!e)return o;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??o}function bt(e,t){if(!e)return o;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??o}class yt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ue,this.graphSettingsCache=new mt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,vt(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,bt(e,t))}async fetchAndBuildHorizonMaps(){try{this._favRefs?await this._buildFavoritesHorizonMaps():(await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings))}catch{}}async _buildFavoritesHorizonMaps(){if(!this._hass||!this._favRefs||!this._topology)return;const e=new Set;for(const t of Object.values(this._favRefs))t.configEntryId&&e.add(t.configEntryId);const t=new Map;await Promise.all(Array.from(e).map(async e=>{t.set(e,await this._fetchGraphSettingsFresh(e))})),this.horizonMap.clear(),this.subDeviceHorizonMap.clear();for(const e of Object.keys(this._topology.circuits)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.horizonMap.set(e,vt(n,s))}if(this._topology.sub_devices)for(const e of Object.keys(this._topology.sub_devices)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.subDeviceHorizonMap.set(e,bt(n,s))}}async loadHistory(){await gt(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??o;if(!a[n]?.useRealtime)continue;const s=qe(i,this._config);if(!s)continue;const r=this._hass.states[s];if(!r)continue;const c=parseFloat(r.state);if(isNaN(c))continue;const l=at(n),d=rt(l),h=ct(l),p=e-l,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of ut(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await gt(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(ft(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ot(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const c=Ye(r);if(c){const e=t.states[c],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${He(n)} ${Ie(n)}`)}const l=i.querySelectorAll("[data-chart-key]");for(const e of l){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let c=_.power;i.endsWith("_soc")?c=_.soc:i.endsWith("_soe")&&(c=_.soe);const l=!!e.closest(".bess-chart-col");_t(e,t,r,o?.has(n)?at(o.get(n)):a,c,!1,l?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this._favRefs?await this._buildFavoritesHorizonMaps():(this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const c=r.entities?.switch;if(!c)return;const l=this._hass.states[c];if(!l)return void console.warn("SPAN Panel: switch entity not found:",c);const d="on"===l.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:c}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const s=t.querySelector("span-side-panel");if(!s||!this._hass)return;if(s.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void s.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,c;t?[r,c]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,c=this.monitoringCache.status);const l=e.entities?.current??e.entities?.power,d=l?c?.circuits?.[l]??null:null,h=r?.global_horizon??o,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void s.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const c=a?.global_horizon??o,l=a?.sub_devices?.[i],d=l?{...l,globalHorizon:c}:{horizon:c,has_override:!1,globalHorizon:c},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;s.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:r,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},c=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},l=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>c(e.clientX)),e.addEventListener("mouseup",l),e.addEventListener("mouseleave",l),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>c(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",l),e.addEventListener("touchcancel",l),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}function wt(e=""){const t=e?` value="${Le(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function xt(e,t,i,s,o,a,r){const l=t.entities?.power,d=l?i.states[l]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===c,_=t.breaker_rating_a,m=_?`${Math.round(_)}A`:"",v=Le(t.name||n("grid.unknown")),b=je(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${He(h)}${Ie(h)}`;else w="";const x=a||"unknown";let S="";if("unknown"!==x){const e=f[x]??f.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};S=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let C="";if(null!=o?.utilization_pct){const e=o.utilization_pct;C=`${Math.round(e)}%`}const E=g?'ON':'OFF';return`\n
\n ${m?`${m}`:""}\n ${v}\n ${S}\n ${C}\n ${E}\n \n ${w}\n \n \n
\n `}function St(e,t,i,n,s,o){const a=Be(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Ct(e){return`
${Le(e)}
`}function Et(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,r=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===c;let l;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;l=n?Math.abs(parseFloat(n.state)||0):0}else l=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:r,value:l}}function $t(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function zt(e,t,i,n){const s=Et(e,i,n),o=Et(t,i,n);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value}function kt(e,t,i){return e.sort((e,n)=>zt(e[1],n[1],t,i))}function At(e){return e.entities?.current??e.entities?.power??""}class Mt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=kt(Object.entries(i.circuits),t,n);let r=o+wt(this._searchQuery);r+='
';for(const[e,i]of a){const o=We(s,At(i)),a=$t(i,t),c=this._expandedUuids.has(e);r+=xt(e,i,t,n,o,a,c),c&&(r+=St(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const c=e.querySelector("span-side-panel");c&&(c.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),c=new Map;for(const[e,t]of Object.entries(i.circuits)){const i=t.area??r,n=c.get(i);n?n.push([e,t]):c.set(i,[[e,t]])}const l=[...c.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+wt(this._searchQuery);d+='
';for(const e of l){const i=c.get(e);if(!i)continue;const n=kt(i,t,s);d+=Ct(e);for(const[e,i]of n){const n=We(o,At(i)),a=$t(i,t),r=this._expandedUuids.has(e);d+=xt(e,i,t,s,n,a,r),r&&(d+=St(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=je(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:c,value:l}=Et(r,t,n),d=e.querySelector(".list-power-value");if(d)if(c)if(o)d.innerHTML=`${s.format(l)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${He(n)}${Ie(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=c?"ON":"OFF",h.classList.toggle("list-status-on",c),h.classList.toggle("list-status-off",!c)),e.classList.toggle("circuit-off",!c)}!function(e,t,i,n){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let i={anchor:null,units:[]};const n=[i],s=[...e.children];for(let e=0;ezt(e.circuit,i.circuit,t,n));if(!i.some((t,i)=>t.uuid!==e.units[i].uuid))continue;let o=e.anchor;for(const e of i)o?o.after(e.row):s.prepend(e.row),o=e.row,e.expanded&&(o.after(e.expanded),o=e.expanded)}}(e,t,i,n)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=We(this._monitoringStatus,At(n)),o=$t(n,this._hass),a=St(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}async function Pt(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let c;if(t.device_id){const e=r.get(t.device_id);e&&(c=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=c),e.area=t}}function Lt(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}function Nt(e){return e?{id:e.id,name:e.name,name_by_user:e.name_by_user,config_entries:e.config_entries,identifiers:e.identifiers,via_device_id:e.via_device_id,sw_version:e.sw_version,model:e.model}:null}const Dt="favorites-changed";async function It(e,t,i={}){const n=await e.callWS({type:"call_service",domain:r,service:t,service_data:i,return_response:!0});return n?.response??null}const Ht=Object.keys(f).filter(e=>"unknown"!==e&&"always_on"!==e);class Tt extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const s=document.createElement("div");s.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",s.appendChild(r);const c=t.graphSettings,l=t.topology,d=c?.global_horizon??o,h=c?.circuits??{},p=document.createElement("div");p.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),p.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const m=document.createElement("select");for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),m.appendChild(t)}if(m.addEventListener("change",()=>{const e={horizon:m.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(m),p.appendChild(_),s.appendChild(p),l?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const o=Object.entries(l.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(s.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&o.appendChild(e)}const c=h[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,p=document.createElement("select");p.dataset.uuid=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),p.appendChild(t)}if(p.addEventListener("change",()=>{this._debounce(`circuit-${i}`,u,()=>{const e={circuit_id:i,horizon:p.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(p),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{p.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}const v=c?.sub_devices??{};if(l?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const o=Object.entries(l.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,s]of o){const o=document.createElement("div");o.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=s.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",o.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(s.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&o.appendChild(e)}const c=v[i]||{horizon:d,has_override:!1},l=c.has_override?c.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(a)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===l&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,u,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),o.appendChild(h),c.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),o.appendChild(e)}e.appendChild(o)}s.appendChild(e)}e.appendChild(s)}_renderCircuitMode(e,t){const i=`${Le(String(t.breaker_rating_a))}A · ${Le(String(t.voltage))}V · Tabs [${Le(String(t.tabs))}]`,n=this._createHeader(Le(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);return i?this._buildHeartButton(i,t):null}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);return i?this._buildHeartButton(i,t):(console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"),null)}_buildHeartButton(e,t){const i=document.createElement("button");i.type="button",i.className=t?"fav-heart active":"fav-heart",i.dataset.role="fav-heart",i.title=n("sidepanel.save_to_favorites"),i.setAttribute("role","switch"),i.setAttribute("aria-pressed",String(t)),i.setAttribute("aria-label",n("sidepanel.save_to_favorites"));const s=document.createElement("ha-icon");return s.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),i.appendChild(s),i.addEventListener("click",t=>{t.stopPropagation(),this._toggleFavoriteEntity(i,s,e).catch(()=>{})}),i}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(o));try{o?await async function(e,t){const i=await It(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Dt)),i?.favorites??{}}(this._hass,i):await async function(e,t){const i=await It(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Dt)),i?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(s));const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites"),o.appendChild(a),o.appendChild(this._buildHeartButton(t,i)),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(Le(t.name),Le(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=Le(e),o=Le(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,c=this._hass?.states?.[r]?.state;"on"===c&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,c=this._hass?.states?.[r]?.state||"";for(const e of Ht){const t=f[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===c&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="section-label",s.textContent=n("sidepanel.graph_horizon"),i.appendChild(s);const r=t.graphHorizonInfo,c=!0===r?.has_override,l=r?.horizon||o,d=r?.globalHorizon||o,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(a))p.push({key:e,label:e});const u=c?l:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,c=null!=r&&!1!==r.monitoring_enabled;c&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const l=document.createElement("div");l.dataset.role="monitoring-details",l.style.display=c?"block":"none",i.appendChild(l);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,l.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),l.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;l.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const m=h.querySelectorAll('input[type="radio"]');for(const e of m)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,c=!1){const l=document.createElement("div");l.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),p=document.createElement("input");p.type="number",p.min=String(s),p.max=String(o),p.value=String(i),p.dataset.role=`threshold-${t}`,c&&(p.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(p),h.appendChild(g),c||p.addEventListener("input",()=>{this._debounce(`threshold-${t}`,u,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),l.appendChild(d),l.appendChild(h),l}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:r,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Tt)}catch{}const Rt=[{name:"Kitchen",watts:"120",path:"M0,28 L8,26 L16,24 L24,22 L32,25 L40,20 L48,18 L56,22 L64,19 L72,16 L80,18 L88,15 L96,17 L104,14 L112,16 L120,13"},{name:"Living Room",watts:"85",path:"M0,22 L8,24 L16,20 L24,26 L32,18 L40,22 L48,16 L56,20 L64,24 L72,18 L80,22 L88,20 L96,16 L104,22 L112,18 L120,20"},{name:"Master Bed",watts:"193",path:"M0,8 L8,10 L16,8 L24,12 L32,10 L40,8 L48,10 L56,8 L64,10 L72,8 L80,12 L88,10 L96,8 L104,10 L112,8 L120,10"},{name:"HVAC",watts:"64",path:"M0,30 L8,28 L16,26 L24,22 L32,18 L40,14 L48,18 L56,22 L64,26 L72,22 L80,18 L88,22 L96,26 L104,22 L112,18 L120,22"}];let Ft=class extends Ee{constructor(){super(...arguments),this._config={},this._discovered=!1,this._discovering=!1,this._discoveryError=null,this._topology=null,this._activeTab="panel",this._panelDevice=null,this._panelSize=0,this._historyLoaded=!1,this._ctrl=new yt,this._listCtrl=new Mt(this._ctrl),this._areaUnsub=null,this._tabBarCleanup=null,this._onVisibilityChange=null}get _configEntryId(){return this._panelDevice?.config_entries?.[0]??null}connectedCallback(){super.connectedCallback(),this._ctrl.startIntervals(this.shadowRoot),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&(this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot))},document.addEventListener("visibilitychange",this._onVisibilityChange)}disconnectedCallback(){this._ctrl.stopIntervals(),this._listCtrl.stop(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),super.disconnectedCallback()}setConfig(e){this._config=e,this._discovered=!1,this._discovering=!1,this._historyLoaded=!1,this._discoveryError=null,this._topology=null,this._panelDevice=null,this._panelSize=0,this._activeTab="panel",this._ctrl.reset(),this._ctrl.setConfig(e)}getCardSize(){return Math.ceil(this._panelSize/2)+3}static getConfigElement(){return document.createElement("span-panel-card-editor")}static getStubConfig(){return{device_id:"",history_days:0,history_hours:0,history_minutes:5,chart_metric:s,show_panel:!0,show_battery:!0,show_evse:!0}}render(){return i(this.hass?.language),this._config.device_id?this._discovered?re`
${Le(n("card.loading"))}
- `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Mt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Pt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Lt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Mt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Lt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Pt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Mt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Re(Math.max(...i));0===Fe(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${He(u)} ${Ie(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Tt.map(e=>re` + `:this._renderPreview()}updated(e){if(e.has("hass")&&this.hass&&(i(this.hass.language),this._ctrl.hass=this.hass,this._config.device_id))if(this._discovered||this._discovering){if(this._discovered){this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot);const e=this.shadowRoot.querySelector("span-side-panel");e&&(e.hass=this.hass)}this._discovered&&"panel"!==this._activeTab&&this._topology&&this._listCtrl.updateCollapsedRows(this.shadowRoot,this.hass,this._topology,this._config)}else this._startDiscovery()}async _startDiscovery(){this._discovering=!0,await this._discoverTopology(),this._discoveryError?this._discovering=!1:(this._discovered=!0,this._discovering=!1,this._ctrl.init(this._topology,this._config,this.hass,this._configEntryId),this._topology&&async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await Pt(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,this._topology,()=>{"area"===this._activeTab&&this._discovered&&this._populateCardContent()}).then(e=>{this._areaUnsub=e}).catch(()=>{}),await this.updateComplete,this._populateCardContent(),this._loadHistory(),this._ctrl.monitoringCache.fetch(this.hass,this._configEntryId).then(()=>{this._discovered&&this._ctrl.updateDOM(this.shadowRoot)}))}async _discoverTopology(){if(this.hass)try{const e=await async function(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${r}/panel_topology`,device_id:t}),s=i.panel_size??Lt(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=Nt((await e.callWS({type:"config/device_registry/list"})).find(e=>e.id===t));return await Pt(e,i),{topology:i,panelDevice:o,panelSize:s}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: topology fetch failed, falling back to entity discovery",e);try{const e=await async function(e,t){const[i,s]=await Promise.all([e.callWS({type:"config/device_registry/list"}),e.callWS({type:"config/entity_registry/list"})]),o=Nt(i.find(e=>e.id===t));if(!o)return{topology:null,panelDevice:null,panelSize:0};const a=s.filter(e=>e.device_id===t),c=i.filter(e=>e.via_device_id===t),l=new Set(c.map(e=>e.id)),d=s.filter(e=>void 0!==e.device_id&&l.has(e.device_id)),h={},p=o.name_by_user??o.name??"";for(const t of[...a,...d]){const i=e.states[t.entity_id];if(!i)continue;const n=i.attributes,s=n.tabs;if("string"!=typeof s||!s.startsWith("tabs ["))continue;const o=s.slice(6,-1);let a;if(a=o.includes(":")?o.split(":").map(Number):[Number(o)],!a.every(Number.isFinite))continue;const r=t.unique_id.split("_");let c=null;for(let e=2;e=16&&/^[a-f0-9]+$/i.test(t)){c=t;break}}if(!c)continue;let l=("string"==typeof n.friendly_name?n.friendly_name:void 0)??t.entity_id;for(const e of[" Power"," Consumed Energy"," Produced Energy"])if(l.endsWith(e)){l=l.slice(0,-e.length);break}p&&l.startsWith(p+" ")&&(l=l.slice(p.length+1));const d=t.entity_id.replace(/^sensor\./,"").replace(/_power$/,""),u="number"==typeof n.voltage?n.voltage:2===a.length?240:120,g={power:t.entity_id,switch:`switch.${d}_breaker`,breaker_rating:`sensor.${d}_breaker_rating`};h[c]={tabs:a,name:l,voltage:u,device_type:"string"==typeof n.device_type?n.device_type:"circuit",relay_state:"string"==typeof n.relay_state?n.relay_state:"UNKNOWN",is_user_controllable:!0,breaker_rating_a:null,entities:g}}let u="";if(o.identifiers)for(const e of o.identifiers)e[0]===r&&(u=e[1]);let g=0;for(const t of a){const i=e.states[t.entity_id];if(i&&"number"==typeof i.attributes.panel_size){g=i.attributes.panel_size;break}}if(g||(g=Lt(h)),!g)throw new Error(n("card.panel_size_error"));const _={};for(const t of c){const i=s.filter(e=>e.device_id===t.id),n=(t.model??"").toLowerCase(),o=n.includes("battery")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("bess")),a=n.includes("drive")||(t.identifiers??[]).some(e=>e[1].toLowerCase().includes("evse")),r={};for(const t of i){const i=t.entity_id.split(".")[0],n=e.states[t.entity_id],s=n?.attributes?.friendly_name;r[t.entity_id]={domain:i??"",original_name:"string"==typeof s?s:t.entity_id}}_[t.id]={name:t.name_by_user??t.name??"",type:o?"bess":a?"evse":"unknown",entities:r}}const f={serial:u,firmware:o.sw_version??"",panel_size:g,device_id:t,device_name:o.name_by_user??o.name??n("header.default_name"),circuits:h,sub_devices:_};return await Pt(e,f),{topology:f,panelDevice:o,panelSize:g}}(this.hass,this._config.device_id);this._topology=e.topology,this._panelDevice=e.panelDevice,this._panelSize=e.panelSize}catch(e){console.error("SPAN Panel: fallback discovery also failed",e),this._discoveryError=e.message}}}async _loadHistory(){if(!this._historyLoaded&&this._topology&&this.hass){this._historyLoaded=!0,await this._ctrl.fetchAndBuildHorizonMaps();try{await this._ctrl.loadHistory(),this._ctrl.updateDOM(this.shadowRoot)}catch(e){console.warn("SPAN Panel: history fetch failed, charts will populate live",e)}}}_populateCardContent(){const e=this.shadowRoot.querySelector("#card-content");if(!(e&&this.hass&&this._topology&&this._panelSize))return;const t=this.shadowRoot.querySelector("#card-tabs");if(t){const e=[{id:"panel",label:n("tab.by_panel"),icon:"mdi:view-dashboard"},{id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"}];t.innerHTML=(i=e,s=this._activeTab,o=this._config.tab_style??"text",`
${i.map(e=>{const t=e.id===s?" active":"",i=Le(e.id);return"icon"===o?``:``}).join("")}
`),this._tabBarCleanup&&(this._tabBarCleanup(),this._tabBarCleanup=null),this._tabBarCleanup=function(e,t){const i=e=>{const i=e.target.closest(".shared-tab");if(i){const e=i.dataset.tab;e&&t(e)}};return e.addEventListener("click",i),()=>{e.removeEventListener("click",i)}}(t,e=>{["panel","activity","area"].includes(e)&&(this._activeTab=e,this._listCtrl.stop(),this._populateCardContent())})}var i,s,o;if("panel"===this._activeTab){const t=Math.ceil(this._panelSize/2),i=Ne(this._topology,this._config),s=this._ctrl.monitoringCache.status,o=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(s),a=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Oe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,c=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Re(Math.max(...i));0===Fe(e)?r.add(n):c.add(n)}function l(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?We(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=l(h);d+=Be(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=Ve(e,"2"));else{const{monInfo:t,sheddingPriority:s}=l(h);d+=Be(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!c.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=Ve(e,"3"));else{const{monInfo:t,sheddingPriority:s}=l(p);d+=Be(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(this._topology,t,this.hass,this._config,s),r=function(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===d&&!s||e.type===h&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===h).length;let c=0,l="";for(const[e,s]of a){const o=s.type===h?n("subdevice.ev_charger"):s.type===d?n("subdevice.battery"):n("subdevice.fallback"),a=Ye(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===d,_=s.type===h,f=g?et(s):null,m=g?tt(s):null,v=g?it(s):null,b=nt(s,t,i,new Set([a,f,m,v].filter(e=>null!==e))),y=st(e,0,g,a,f,m);let w="";g?w="sub-device-bess":_&&(c++,c===r&&r%2==1&&(w="sub-device-full")),l+=`\n
\n
\n ${Le(o)}\n ${Le(s.name||"")}\n ${a?`${He(u)} ${Ie(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return l}(this._topology,this.hass,this._config);e.innerHTML=`\n ${i}\n ${o}\n ${r?`
${r}
`:""}\n ${!1!==this._config.show_panel?`
${a}
`:""}\n `;const c=e.querySelector(".slide-confirm");if(c){const e=this.shadowRoot.querySelector("ha-card");this._ctrl.bindSlideConfirm(c,e),e&&e.classList.add("switches-disabled")}const l=this.shadowRoot.querySelector("span-side-panel");l&&(l.hass=this.hass),this._ctrl.recordSamples(),this._ctrl.updateDOM(this.shadowRoot),this._ctrl.setupResizeObserver(this.shadowRoot,this.shadowRoot.querySelector("ha-card"))}else if("activity"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderActivityView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}else if("area"===this._activeTab){e.innerHTML="";const t=Ne(this._topology,this._config,{showSwitches:!1});this._listCtrl.renderAreaView(e,this.hass,this._topology,this._config,this._ctrl.monitoringCache.status,t),this._ctrl.updateDOM(this.shadowRoot)}}_onCardClick(e){if("panel"!==this._activeTab)return;const t=e.target;if(!t)return;const i=t.closest(".unit-btn");if(i)return void this._onUnitToggle(i);if(t.closest(".toggle-pill"))return void this._ctrl.onToggleClick(e,this.shadowRoot);t.closest(".gear-icon")&&this._ctrl.onGearClick(e,this.shadowRoot)}async _onUnitToggle(e){const t=e.dataset.unit;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}async _onListUnitChanged(e){const t=e.detail;t&&t!==(this._config.chart_metric??"power")&&(this._config={...this._config,chart_metric:t},this._ctrl.setConfig(this._config),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0})),this._ctrl.powerHistory.clear(),this._historyLoaded=!1,this._populateCardContent(),await this._loadHistory(),this._ctrl.updateDOM(this.shadowRoot))}_onGraphSettingsChanged(){this._ctrl.onGraphSettingsChanged(this.shadowRoot)}_onSidePanelClosed(){this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()}_renderPreview(){const e=Rt.map(e=>re`
${e.name} @@ -78,4 +78,4 @@ const ze={attribute:!0,type:String,converter:T,reflect:!1,hasChanged:R},ke=(e=ze
${n("card.no_device")}
- `}};Rt.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],Rt.prototype,"hass",void 0),v([Me()],Rt.prototype,"_config",void 0),v([Me()],Rt.prototype,"_discovered",void 0),v([Me()],Rt.prototype,"_discovering",void 0),v([Me()],Rt.prototype,"_discoveryError",void 0),v([Me()],Rt.prototype,"_topology",void 0),v([Me()],Rt.prototype,"_activeTab",void 0),Rt=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],Rt);class Ft extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",Ft)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); + `}};Ft.styles=C("\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n"),v([Ae({attribute:!1})],Ft.prototype,"hass",void 0),v([Me()],Ft.prototype,"_config",void 0),v([Me()],Ft.prototype,"_discovered",void 0),v([Me()],Ft.prototype,"_discovering",void 0),v([Me()],Ft.prototype,"_discoveryError",void 0),v([Me()],Ft.prototype,"_topology",void 0),v([Me()],Ft.prototype,"_activeTab",void 0),Ft=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel-card")],Ft);class Ot extends HTMLElement{constructor(){super(...arguments),this._config={},this._hass=null,this._panels=null,this._availableRoles=null,this._built=!1,this._panelSelect=null,this._daysInput=null,this._hoursInput=null,this._minsInput=null,this._metricSelect=null,this._checkboxes={},this._entityContainers={},this._tabStyleSelect=null}setConfig(e){this._config={...e},this._updateControls()}set hass(e){this._hass=e,this._panels?this._built||this._buildEditor():this._discoverPanels()}async _discoverPanels(){if(!this._hass)return;const e=await this._hass.callWS({type:"config/device_registry/list"});this._panels=e.filter(e=>(e.identifiers??[]).some(e=>e[0]===r)&&!e.via_device_id).map(e=>{const t=(e.identifiers??[]).find(e=>e[0]===r)?.[1]??"",i=e.name_by_user??e.name??n("editor.panel_label");return{device_id:e.id,label:`${i} (${t})`}}),this._buildEditor()}_buildEditor(){this.innerHTML="",this._built=!0;const e=document.createElement("div");e.style.padding="16px";const t="\n width: 100%;\n padding: 10px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--card-background-color, var(--secondary-background-color, #1c1c1c));\n color: var(--primary-text-color, #e0e0e0);\n font-size: 1em;\n cursor: pointer;\n appearance: auto;\n box-sizing: border-box;\n ",i="display: block; font-weight: 500; margin-bottom: 8px; color: var(--primary-text-color);",n="margin-bottom: 16px;";this._buildPanelSelector(e,t,i,n),this._buildTimeWindow(e,t,i,n),this._buildMetricSelector(e,t,i,n),this._buildTabStyleSelector(e,t,i,n),this._buildSectionCheckboxes(e,i,n),this.appendChild(e),this._populateMetricSelect(),this._config.device_id&&this._discoverAvailableRoles(this._config.device_id)}_buildPanelSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.panel_label"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=document.createElement("option");if(c.value="",c.textContent=n("editor.select_panel"),r.appendChild(c),this._panels)for(const e of this._panels){const t=document.createElement("option");t.value=e.device_id,t.textContent=e.label,e.device_id===this._config.device_id&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,device_id:r.value},this._fireConfigChanged(),this._discoverAvailableRoles(r.value)}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._panelSelect=r}_buildTimeWindow(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_window"),a.style.cssText=i;const r=document.createElement("div");r.style.cssText="display: flex; gap: 12px; align-items: center; flex-wrap: wrap;";const c=t+"width: 70px; cursor: text;",l=(e,t,i,n)=>{const s=document.createElement("div");s.style.cssText="display: flex; align-items: center; gap: 6px;";const o=document.createElement("input");o.type="number",o.min=t,o.max=i,o.value=String(e),o.style.cssText=c;const a=document.createElement("span");return a.textContent=n,a.style.cssText="font-size: 0.9em; color: var(--secondary-text-color);",s.appendChild(o),s.appendChild(a),{wrap:s,input:o}},d=parseInt(String(this._config.history_days))||0,h=parseInt(String(this._config.history_hours))||0,p=parseInt(String(this._config.history_minutes))||0,u=l(d,"0","30",n("editor.days")),g=l(h,"0","23",n("editor.hours")),_=l(p,"0","59",n("editor.minutes")),f=()=>{this._config={...this._config,history_days:parseInt(u.input.value)||0,history_hours:parseInt(g.input.value)||0,history_minutes:parseInt(_.input.value)||0},this._fireConfigChanged()};u.input.addEventListener("change",f),g.input.addEventListener("change",f),_.input.addEventListener("change",f),r.appendChild(u.wrap),r.appendChild(g.wrap),r.appendChild(_.wrap),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._daysInput=u.input,this._hoursInput=g.input,this._minsInput=_.input}_buildMetricSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.chart_metric"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t,r.addEventListener("change",()=>{this._config={...this._config,chart_metric:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._metricSelect=r}_buildTabStyleSelector(e,t,i,s){const o=document.createElement("div");o.style.cssText=s;const a=document.createElement("label");a.textContent=n("editor.tab_style"),a.style.cssText=i;const r=document.createElement("select");r.style.cssText=t;const c=[{value:"text",text:n("editor.tab_style_text")},{value:"icon",text:n("editor.tab_style_icon")}];for(const e of c){const t=document.createElement("option");t.value=e.value,t.textContent=e.text,e.value===(this._config.tab_style??"text")&&(t.selected=!0),r.appendChild(t)}r.addEventListener("change",()=>{this._config={...this._config,tab_style:r.value},this._fireConfigChanged()}),o.appendChild(a),o.appendChild(r),e.appendChild(o),this._tabStyleSelect=r}_buildSectionCheckboxes(e,t,i){const s=document.createElement("div");s.style.cssText=i;const o=document.createElement("label");o.textContent=n("editor.visible_sections"),o.style.cssText=t,s.appendChild(o);const a=[{key:"show_panel",label:n("editor.panel_circuits"),subDeviceType:null},{key:"show_battery",label:n("editor.battery_bess"),subDeviceType:"bess"},{key:"show_evse",label:n("editor.ev_charger_evse"),subDeviceType:"evse"}];this._checkboxes={},this._entityContainers={};for(const e of a){const t=document.createElement("div");t.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 6px; cursor: pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1!==this._config[e.key],i.style.cssText="width: 18px; height: 18px; cursor: pointer; accent-color: var(--primary-color);";const n=document.createElement("span");n.textContent=e.label,n.style.cssText="font-size: 0.9em; color: var(--primary-text-color); cursor: pointer;",t.appendChild(i),t.appendChild(n),s.appendChild(t),this._checkboxes[e.key]=i;let o=null;e.subDeviceType&&(o=document.createElement("div"),o.style.cssText="padding-left: 26px;",o.style.display=i.checked?"block":"none",s.appendChild(o),this._entityContainers[e.subDeviceType]=o),i.addEventListener("change",()=>{this._config={...this._config,[e.key]:i.checked},o&&(o.style.display=i.checked?"block":"none"),this._fireConfigChanged()})}e.appendChild(s)}_isChartEntity(e,t,i){const n=(t.original_name??"").toLowerCase(),s=t.unique_id??"";if("power"===n||"battery power"===n||s.endsWith("_power"))return!0;if("bess"===i){if("battery level"===n||"battery percentage"===n||s.endsWith("_battery_level")||s.endsWith("_battery_percentage"))return!0;if("state of energy"===n||s.endsWith("_soe_kwh"))return!0;if("nameplate capacity"===n||s.endsWith("_nameplate_capacity"))return!0}return!1}_populateEntityCheckboxes(e){const t=this._config.visible_sub_entities??{};for(const[,i]of Object.entries(e)){const e=i.type?this._entityContainers[i.type]:void 0;if(e&&(e.innerHTML="",i.entities))for(const[n,s]of Object.entries(i.entities)){if("sensor"===s.domain&&this._isChartEntity(n,s,i.type??""))continue;const o=document.createElement("div");o.style.cssText="display: flex; align-items: center; gap: 8px; margin-bottom: 5px; cursor: pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!0===t[n],a.style.cssText="width: 16px; height: 16px; cursor: pointer; accent-color: var(--primary-color);";const r=document.createElement("span");let c=s.original_name??n;const l=i.name??"";c.startsWith(l+" ")&&(c=c.slice(l.length+1)),r.textContent=c,r.style.cssText="font-size: 0.85em; color: var(--primary-text-color); cursor: pointer;",o.appendChild(a),o.appendChild(r),e.appendChild(o),a.addEventListener("change",()=>{const e={...this._config.visible_sub_entities??{}};a.checked?e[n]=!0:delete e[n],this._config={...this._config,visible_sub_entities:e},this._fireConfigChanged()})}}}async _discoverAvailableRoles(e){if(this._hass&&e)try{const t=await this._hass.callWS({type:`${r}/panel_topology`,device_id:e}),i=new Set;for(const e of Object.values(t.circuits??{}))for(const t of Object.keys(e.entities??{}))i.add(t);this._availableRoles=i,this._populateMetricSelect(),t.sub_devices&&this._populateEntityCheckboxes(t.sub_devices)}catch{this._availableRoles=null,this._populateMetricSelect()}}_populateMetricSelect(){const e=this._metricSelect;if(!e)return;const t=this._config.chart_metric??s;e.innerHTML="";for(const[i,n]of Object.entries(g)){if(this._availableRoles&&!this._availableRoles.has(n.entityRole))continue;const s=document.createElement("option");s.value=i,s.textContent=n.label(),i===t&&(s.selected=!0),e.appendChild(s)}}_updateControls(){if(this._panelSelect&&(this._panelSelect.value=this._config.device_id??""),this._daysInput&&(this._daysInput.value=String(parseInt(String(this._config.history_days))||0)),this._hoursInput&&(this._hoursInput.value=String(parseInt(String(this._config.history_hours))||0)),this._minsInput&&(this._minsInput.value=String(parseInt(String(this._config.history_minutes))||0)),this._metricSelect&&(this._metricSelect.value=this._config.chart_metric??s),this._checkboxes)for(const[e,t]of Object.entries(this._checkboxes))t.checked=!1!==this._config[e];this._tabStyleSelect&&(this._tabStyleSelect.value=this._config.tab_style??"text")}_fireConfigChanged(){this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}}try{customElements.get("span-panel-card-editor")||customElements.define("span-panel-card-editor",Ot)}catch{}window.customCards=window.customCards??[],window.customCards.push({type:"span-panel-card",name:"SPAN Panel",description:"Physical panel layout with live power charts matching the SPAN frontend",preview:!0}),console.warn("%c SPAN-PANEL-CARD %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: var(--text-primary-color, #000); font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;"); diff --git a/dist/span-panel.js b/dist/span-panel.js index f3d34af..e44dc8b 100644 --- a/dist/span-panel.js +++ b/dist/span-panel.js @@ -1,37 +1,37 @@ -let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 favorite","panel.favorites_summary_many":"{circuits} favorites","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 favori","panel.favorites_summary_many":"{circuits} favoris","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"お気に入り 1 件","panel.favorites_summary_many":"お気に入り {circuits} 件","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function i(i){return t[e]?.[i]??t.en?.[i]??i}const n="power",s="5m",o={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},a="span_panel",r="CLOSED",l="pv",c="bess",d="evse",h="sub_",p=500,u={power:{entityRole:"power",label:()=>i("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>i("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},g={soc:{entityRole:"soc",label:()=>i("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>i("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:u.power},_={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>i("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>i("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>i("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>i("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>i("shedding.unknown")}},f="#ff9800";function v(e,t,i,n){var s,o=arguments.length,a=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,n);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,i,a):s(t,i))||a);return o>3&&a&&Object.defineProperty(t,i,a),a}"function"==typeof SuppressedError&&SuppressedError; +let e="en";const t={en:{"tab.panel":"Panel","tab.by_panel":"By Panel","tab.by_activity":"By Activity","tab.by_area":"By Area","tab.monitoring":"Monitoring","tab.settings":"Settings","list.search_placeholder":"Search circuits...","list.unassigned_area":"Unassigned","list.no_results":"No circuits found","monitoring.heading":"Monitoring","monitoring.global_settings":"Global Settings","monitoring.enabled":"Enabled","monitoring.continuous":"Continuous (%)","monitoring.spike":"Spike (%)","monitoring.window":"Window (min)","monitoring.cooldown":"Cooldown (min)","monitoring.monitored_points":"Monitored Points","monitoring.col.name":"Name","monitoring.col.continuous":"Continuous","monitoring.col.spike":"Spike","monitoring.col.window":"Window","monitoring.col.cooldown":"Cooldown","monitoring.all_none":"All / None","monitoring.reset":"Reset","notification.heading":"Notification Settings","notification.targets":"Notify Targets","notification.none_selected":"None selected","notification.no_targets":"No notify targets found","notification.all_targets":"All","notification.event_bus_target":"Event Bus (HA event bus)","notification.priority":"Priority","notification.priority.default":"Default","notification.priority.passive":"Passive","notification.priority.active":"Active","notification.priority.time_sensitive":"Time-sensitive","notification.priority.critical":"Critical","notification.hint.critical":"Overrides silent/DND","notification.hint.time_sensitive":"Breaks through Focus","notification.hint.passive":"Delivers silently","notification.hint.active":"Standard delivery","notification.title_template":"Title Template","notification.message_template":"Message Template","notification.placeholders":"Placeholders:","notification.event_bus_help":"Event Bus fires event type","notification.event_bus_payload":"with payload:","notification.test_label":"Test Notification","notification.test_button":"Send Test","notification.test_sending":"Sending...","notification.test_sent":"Test notification sent","error.prefix":"Error:","error.failed_save":"Failed to save","error.failed":"Failed","settings.heading":"Settings","settings.description":"General integration settings (entity naming, device prefix, circuit numbers) are managed through the integration's options flow.","settings.open_link":"Open SPAN Panel Integration Settings","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Panel monitoring settings","header.graph_settings":"Graph time horizon settings","header.site":"Site","header.grid":"Grid","header.upstream":"Upstream","header.downstream":"Downstream","header.solar":"Solar","header.battery":"Battery","header.toggle_units":"Toggle Watts / Amps","header.enable_switches":"Enable Switches","header.switches_enabled":"Switches Enabled","grid.unknown":"Unknown","grid.configure":"Configure circuit","grid.configure_subdevice":"Configure device","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"EV Charger","subdevice.battery":"Battery","subdevice.fallback":"Sub-device","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Power","sidepanel.graph_settings":"Graph Settings","sidepanel.global_defaults":"Global defaults for all circuits","sidepanel.global_default":"Global Default","sidepanel.circuit_scales":"Circuit Graph Scales","sidepanel.subdevice_scales":"Sub-Device Graph Scales","sidepanel.reset_to_global":"Reset to global default","sidepanel.relay":"Relay","sidepanel.breaker":"Breaker","sidepanel.relay_failed":"Relay toggle failed:","sidepanel.shedding_priority":"Shedding Priority","sidepanel.priority_label":"Priority","sidepanel.shedding_failed":"Shedding update failed:","sidepanel.monitoring":"Monitoring","sidepanel.global":"Global","sidepanel.custom":"Custom","sidepanel.continuous_pct":"Continuous %","sidepanel.spike_pct":"Spike %","sidepanel.window_duration":"Window duration","sidepanel.cooldown":"Cooldown","sidepanel.monitoring_toggle_failed":"Monitoring toggle failed:","sidepanel.clear_monitoring_failed":"Clear monitoring failed:","sidepanel.save_threshold_failed":"Save threshold failed:","sidepanel.favorite":"Favorite","sidepanel.save_to_favorites":"Save to favorites","sidepanel.favorite_failed":"Favorite update failed:","panel.favorites":"Favorites","panel.favorites_summary_one":"1 favorite","panel.favorites_summary_many":"{circuits} favorites","status.monitoring":"Monitoring","status.circuits":"circuits","status.mains":"mains","status.warning":"warning","status.warnings":"warnings","status.alert":"alert","status.alerts":"alerts","status.override":"override","status.overrides":"overrides","card.no_device":"Open the card editor and select your SPAN Panel device.","card.device_not_found":"Panel device not found. Check device_id in card config.","card.loading":"Loading...","card.topology_error":"Topology response missing panel_size and no circuits found. Update the SPAN Panel integration.","card.panel_size_error":"Could not determine panel_size. No circuits found and no panel_size attribute. Update the SPAN Panel integration.","editor.panel_label":"SPAN Panel","editor.select_panel":"Select a panel...","editor.chart_window":"Chart time window","editor.days":"days","editor.hours":"hours","editor.minutes":"minutes","editor.chart_metric":"Chart metric","editor.visible_sections":"Visible sections","editor.panel_circuits":"Panel circuits","editor.battery_bess":"Battery (BESS)","editor.ev_charger_evse":"EV Charger (EVSE)","editor.tab_style":"Tab Style","editor.tab_style_text":"Text","editor.tab_style_icon":"Icon","metric.power":"Power","metric.current":"Current","metric.soc":"State of Charge","metric.soe":"State of Energy","shedding.always_on":"Critical","shedding.never":"Non-sheddable","shedding.soc_threshold":"SoC Threshold","shedding.off_grid":"Sheddable","shedding.unknown":"Unknown","shedding.select.never":"Stays on in an outage","shedding.select.soc_threshold":"Stays on until battery threshold","shedding.select.off_grid":"Turns off in an outage"},es:{"tab.panel":"Panel","tab.by_panel":"Por Panel","tab.by_activity":"Por Actividad","tab.by_area":"Por Área","tab.monitoring":"Monitoreo","tab.settings":"Configuración","list.search_placeholder":"Buscar circuitos...","list.unassigned_area":"Sin asignar","list.no_results":"No se encontraron circuitos","monitoring.heading":"Monitoreo","monitoring.global_settings":"Configuración Global","monitoring.enabled":"Activado","monitoring.continuous":"Continuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Ventana (min)","monitoring.cooldown":"Enfriamiento (min)","monitoring.monitored_points":"Puntos Monitoreados","monitoring.col.name":"Nombre","monitoring.col.continuous":"Continuo","monitoring.col.spike":"Pico","monitoring.col.window":"Ventana","monitoring.col.cooldown":"Enfriamiento","monitoring.all_none":"Todos / Ninguno","monitoring.reset":"Restablecer","notification.heading":"Configuración de Notificaciones","notification.targets":"Destinos de Notificación","notification.none_selected":"Ninguno seleccionado","notification.no_targets":"No se encontraron destinos de notificación","notification.all_targets":"Todos","notification.event_bus_target":"Bus de Eventos (bus de eventos de HA)","notification.priority":"Prioridad","notification.priority.default":"Predeterminado","notification.priority.passive":"Pasivo","notification.priority.active":"Activo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Anula silencio/No molestar","notification.hint.time_sensitive":"Atraviesa el modo Concentración","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega estándar","notification.title_template":"Plantilla de Título","notification.message_template":"Plantilla de Mensaje","notification.placeholders":"Variables:","notification.event_bus_help":"El Bus de Eventos dispara el tipo de evento","notification.event_bus_payload":"con datos:","notification.test_label":"Notificación de prueba","notification.test_button":"Enviar prueba","notification.test_sending":"Enviando...","notification.test_sent":"Notificación de prueba enviada","error.prefix":"Error:","error.failed_save":"Error al guardar","error.failed":"Falló","settings.heading":"Configuración","settings.description":"La configuración general de la integración (nombres de entidades, prefijo de dispositivo, números de circuito) se administra a través del flujo de opciones de la integración.","settings.open_link":"Abrir Configuración de Integración SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configuración de monitoreo del panel","header.graph_settings":"Configuración del horizonte temporal del gráfico","header.site":"Sitio","header.grid":"Red","header.upstream":"Aguas arriba","header.downstream":"Aguas abajo","header.solar":"Solar","header.battery":"Batería","header.toggle_units":"Alternar Watts / Amperios","header.enable_switches":"Habilitar Interruptores","header.switches_enabled":"Interruptores Habilitados","grid.unknown":"Desconocido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Enc","grid.off":"Apag","subdevice.ev_charger":"Cargador EV","subdevice.battery":"Batería","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potencia","sidepanel.graph_settings":"Configuración de Gráficos","sidepanel.global_defaults":"Valores predeterminados globales para todos los circuitos","sidepanel.global_default":"Predeterminado Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Restablecer al valor global","sidepanel.relay":"Relé","sidepanel.breaker":"Interruptor","sidepanel.relay_failed":"Error al cambiar relé:","sidepanel.shedding_priority":"Prioridad de Desconexción","sidepanel.priority_label":"Prioridad","sidepanel.shedding_failed":"Error al actualizar desconexción:","sidepanel.monitoring":"Monitoreo","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Continuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duración de ventana","sidepanel.cooldown":"Enfriamiento","sidepanel.monitoring_toggle_failed":"Error al cambiar monitoreo:","sidepanel.clear_monitoring_failed":"Error al limpiar monitoreo:","sidepanel.save_threshold_failed":"Error al guardar umbral:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Guardar en favoritos","sidepanel.favorite_failed":"Error al actualizar favoritos:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoreo","status.circuits":"circuitos","status.mains":"alimentación","status.warning":"advertencia","status.warnings":"advertencias","status.alert":"alerta","status.alerts":"alertas","status.override":"anulación","status.overrides":"anulaciones","card.no_device":"Abra el editor de tarjeta y seleccione su dispositivo SPAN Panel.","card.device_not_found":"Dispositivo de panel no encontrado. Verifique device_id en la configuración de la tarjeta.","card.loading":"Cargando...","card.topology_error":"La respuesta de topología no contiene panel_size y no se encontraron circuitos. Actualice la integración SPAN Panel.","card.panel_size_error":"No se pudo determinar panel_size. No se encontraron circuitos ni atributo panel_size. Actualice la integración SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Seleccione un panel...","editor.chart_window":"Ventana de tiempo del gráfico","editor.days":"días","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica del gráfico","editor.visible_sections":"Secciones visibles","editor.panel_circuits":"Circuitos del panel","editor.battery_bess":"Batería (BESS)","editor.ev_charger_evse":"Cargador EV (EVSE)","editor.tab_style":"Estilo de pestañas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícono","metric.power":"Potencia","metric.current":"Corriente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energía","shedding.always_on":"Crítico","shedding.never":"No desconectable","shedding.soc_threshold":"Umbral SoC","shedding.off_grid":"Desconectable","shedding.unknown":"Desconocido","shedding.select.never":"Permanece encendido en un corte","shedding.select.soc_threshold":"Encendido hasta umbral de batería","shedding.select.off_grid":"Se apaga en un corte"},fr:{"tab.panel":"Panneau","tab.by_panel":"Par Panneau","tab.by_activity":"Par Activité","tab.by_area":"Par Zone","tab.monitoring":"Surveillance","tab.settings":"Paramètres","list.search_placeholder":"Rechercher des circuits...","list.unassigned_area":"Non attribué","list.no_results":"Aucun circuit trouvé","monitoring.heading":"Surveillance","monitoring.global_settings":"Paramètres Globaux","monitoring.enabled":"Activé","monitoring.continuous":"Continu (%)","monitoring.spike":"Pic (%)","monitoring.window":"Fenêtre (min)","monitoring.cooldown":"Refroidissement (min)","monitoring.monitored_points":"Points Surveillés","monitoring.col.name":"Nom","monitoring.col.continuous":"Continu","monitoring.col.spike":"Pic","monitoring.col.window":"Fenêtre","monitoring.col.cooldown":"Refroidissement","monitoring.all_none":"Tous / Aucun","monitoring.reset":"Réinitialiser","notification.heading":"Paramètres de Notification","notification.targets":"Cibles de Notification","notification.none_selected":"Aucune sélection","notification.no_targets":"Aucune cible de notification trouvée","notification.all_targets":"Tous","notification.event_bus_target":"Bus d'événements (bus d'événements HA)","notification.priority":"Priorité","notification.priority.default":"Par défaut","notification.priority.passive":"Passif","notification.priority.active":"Actif","notification.priority.time_sensitive":"Urgent","notification.priority.critical":"Critique","notification.hint.critical":"Outrepasse silencieux/NPD","notification.hint.time_sensitive":"Traverse le mode Concentration","notification.hint.passive":"Livraison silencieuse","notification.hint.active":"Livraison standard","notification.title_template":"Modèle de Titre","notification.message_template":"Modèle de Message","notification.placeholders":"Variables :","notification.event_bus_help":"Le Bus d'événements déclenche le type d'événement","notification.event_bus_payload":"avec les données :","notification.test_label":"Notification de test","notification.test_button":"Envoyer un test","notification.test_sending":"Envoi...","notification.test_sent":"Notification de test envoyée","error.prefix":"Erreur :","error.failed_save":"Échec de la sauvegarde","error.failed":"Échoué","settings.heading":"Paramètres","settings.description":"Les paramètres généraux de l'intégration (noms d'entités, préfixe de l'appareil, numéros de circuit) sont gérés via le flux d'options de l'intégration.","settings.open_link":"Ouvrir les Paramètres d'Intégration SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Paramètres de surveillance du panneau","header.graph_settings":"Paramètres d'horizon temporel du graphique","header.site":"Site","header.grid":"Réseau","header.upstream":"Amont","header.downstream":"Aval","header.solar":"Solaire","header.battery":"Batterie","header.toggle_units":"Basculer Watts / Ampères","header.enable_switches":"Activer les interrupteurs","header.switches_enabled":"Interrupteurs activés","grid.unknown":"Inconnu","grid.configure":"Configurer le circuit","grid.configure_subdevice":"Configurer l'appareil","grid.on":"On","grid.off":"Off","subdevice.ev_charger":"Chargeur VE","subdevice.battery":"Batterie","subdevice.fallback":"Sous-appareil","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Puissance","sidepanel.graph_settings":"Paramètres des Graphiques","sidepanel.global_defaults":"Valeurs par défaut globales pour tous les circuits","sidepanel.global_default":"Défaut Global","sidepanel.circuit_scales":"Échelles des Graphiques de Circuits","sidepanel.subdevice_scales":"Échelles des Graphiques de Sous-Appareils","sidepanel.reset_to_global":"Réinitialiser à la valeur globale","sidepanel.relay":"Relais","sidepanel.breaker":"Disjoncteur","sidepanel.relay_failed":"Échec du basculement du relais :","sidepanel.shedding_priority":"Priorité de Délestage","sidepanel.priority_label":"Priorité","sidepanel.shedding_failed":"Échec de la mise à jour du délestage :","sidepanel.monitoring":"Surveillance","sidepanel.global":"Global","sidepanel.custom":"Personnalisé","sidepanel.continuous_pct":"Continu %","sidepanel.spike_pct":"Pic %","sidepanel.window_duration":"Durée de fenêtre","sidepanel.cooldown":"Refroidissement","sidepanel.monitoring_toggle_failed":"Échec du basculement de surveillance :","sidepanel.clear_monitoring_failed":"Échec de l'effacement de surveillance :","sidepanel.save_threshold_failed":"Échec de la sauvegarde du seuil :","sidepanel.favorite":"Favori","sidepanel.save_to_favorites":"Enregistrer dans les favoris","sidepanel.favorite_failed":"Échec de la mise à jour du favori :","panel.favorites":"Favoris","panel.favorites_summary_one":"1 favori","panel.favorites_summary_many":"{circuits} favoris","status.monitoring":"Surveillance","status.circuits":"circuits","status.mains":"alimentation","status.warning":"avertissement","status.warnings":"avertissements","status.alert":"alerte","status.alerts":"alertes","status.override":"remplacement","status.overrides":"remplacements","card.no_device":"Ouvrez l'éditeur de carte et sélectionnez votre appareil SPAN Panel.","card.device_not_found":"Appareil de panneau introuvable. Vérifiez device_id dans la configuration de la carte.","card.loading":"Chargement...","card.topology_error":"La réponse de topologie ne contient pas panel_size et aucun circuit trouvé. Mettez à jour l'intégration SPAN Panel.","card.panel_size_error":"Impossible de déterminer panel_size. Aucun circuit trouvé et aucun attribut panel_size. Mettez à jour l'intégration SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Sélectionnez un panneau...","editor.chart_window":"Fenêtre de temps du graphique","editor.days":"jours","editor.hours":"heures","editor.minutes":"minutes","editor.chart_metric":"Métrique du graphique","editor.visible_sections":"Sections visibles","editor.panel_circuits":"Circuits du panneau","editor.battery_bess":"Batterie (BESS)","editor.ev_charger_evse":"Chargeur VE (EVSE)","editor.tab_style":"Style des onglets","editor.tab_style_text":"Texte","editor.tab_style_icon":"Icône","metric.power":"Puissance","metric.current":"Courant","metric.soc":"État de Charge","metric.soe":"État d'Énergie","shedding.always_on":"Critique","shedding.never":"Non délestable","shedding.soc_threshold":"Seuil SoC","shedding.off_grid":"Délestable","shedding.unknown":"Inconnu","shedding.select.never":"Reste allumé en cas de coupure","shedding.select.soc_threshold":"Allumé jusqu'au seuil batterie","shedding.select.off_grid":"S'éteint en cas de coupure"},ja:{"tab.panel":"パネル","tab.by_panel":"パネル別","tab.by_activity":"活動別","tab.by_area":"エリア別","tab.monitoring":"モニタリング","tab.settings":"設定","list.search_placeholder":"回路を検索...","list.unassigned_area":"未割り当て","list.no_results":"回路が見つかりません","monitoring.heading":"モニタリング","monitoring.global_settings":"グローバル設定","monitoring.enabled":"有効","monitoring.continuous":"継続 (%)","monitoring.spike":"スパイク (%)","monitoring.window":"ウィンドウ (分)","monitoring.cooldown":"クールダウン (分)","monitoring.monitored_points":"監視ポイント","monitoring.col.name":"名前","monitoring.col.continuous":"継続","monitoring.col.spike":"スパイク","monitoring.col.window":"ウィンドウ","monitoring.col.cooldown":"クールダウン","monitoring.all_none":"全選択 / 全解除","monitoring.reset":"リセット","notification.heading":"通知設定","notification.targets":"通知先","notification.none_selected":"未選択","notification.no_targets":"通知先が見つかりません","notification.all_targets":"すべて","notification.event_bus_target":"イベントバス (HAイベントバス)","notification.priority":"優先度","notification.priority.default":"デフォルト","notification.priority.passive":"パッシブ","notification.priority.active":"アクティブ","notification.priority.time_sensitive":"緊急","notification.priority.critical":"重大","notification.hint.critical":"サイレント/おやすみモードを無視","notification.hint.time_sensitive":"集中モードを突破","notification.hint.passive":"サイレント配信","notification.hint.active":"標準配信","notification.title_template":"タイトルテンプレート","notification.message_template":"メッセージテンプレート","notification.placeholders":"プレースホルダー:","notification.event_bus_help":"イベントバスが発行するイベントタイプ","notification.event_bus_payload":"ペイロード:","notification.test_label":"テスト通知","notification.test_button":"テスト送信","notification.test_sending":"送信中...","notification.test_sent":"テスト通知を送信しました","error.prefix":"エラー:","error.failed_save":"保存に失敗","error.failed":"失敗","settings.heading":"設定","settings.description":"統合の一般設定(エンティティ名、デバイスプレフィックス、回路番号)は統合のオプションフローで管理されます。","settings.open_link":"SPAN Panel統合設定を開く","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"パネルモニタリング設定","header.graph_settings":"グラフ時間範囲設定","header.site":"サイト","header.grid":"グリッド","header.upstream":"上流","header.downstream":"下流","header.solar":"ソーラー","header.battery":"バッテリー","header.toggle_units":"ワット/アンペア切り替え","header.enable_switches":"スイッチを有効化","header.switches_enabled":"スイッチ有効","grid.unknown":"不明","grid.configure":"回路を設定","grid.configure_subdevice":"デバイスを設定","grid.on":"オン","grid.off":"オフ","subdevice.ev_charger":"EV充電器","subdevice.battery":"バッテリー","subdevice.fallback":"サブデバイス","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"電力","sidepanel.graph_settings":"グラフ設定","sidepanel.global_defaults":"全回路のグローバルデフォルト","sidepanel.global_default":"グローバルデフォルト","sidepanel.circuit_scales":"回路グラフスケール","sidepanel.subdevice_scales":"サブデバイスグラフスケール","sidepanel.reset_to_global":"グローバルにリセット","sidepanel.relay":"リレー","sidepanel.breaker":"ブレーカー","sidepanel.relay_failed":"リレー切り替え失敗:","sidepanel.shedding_priority":"シェディング優先度","sidepanel.priority_label":"優先度","sidepanel.shedding_failed":"シェディング更新失敗:","sidepanel.monitoring":"モニタリング","sidepanel.global":"グローバル","sidepanel.custom":"カスタム","sidepanel.continuous_pct":"継続 %","sidepanel.spike_pct":"スパイク %","sidepanel.window_duration":"ウィンドウ時間","sidepanel.cooldown":"クールダウン","sidepanel.monitoring_toggle_failed":"モニタリング切り替え失敗:","sidepanel.clear_monitoring_failed":"モニタリングクリア失敗:","sidepanel.save_threshold_failed":"しきい値保存失敗:","sidepanel.favorite":"お気に入り","sidepanel.save_to_favorites":"お気に入りに保存","sidepanel.favorite_failed":"お気に入りの更新に失敗:","panel.favorites":"お気に入り","panel.favorites_summary_one":"お気に入り 1 件","panel.favorites_summary_many":"お気に入り {circuits} 件","status.monitoring":"モニタリング","status.circuits":"回路","status.mains":"主電源","status.warning":"警告","status.warnings":"警告","status.alert":"アラート","status.alerts":"アラート","status.override":"上書き","status.overrides":"上書き","card.no_device":"カードエディタを開いてSPAN Panelデバイスを選択してください。","card.device_not_found":"パネルデバイスが見つかりません。カード設定のdevice_idを確認してください。","card.loading":"読み込み中...","card.topology_error":"トポロジー応答にpanel_sizeがなく、回路が見つかりません。SPAN Panel統合を更新してください。","card.panel_size_error":"panel_sizeを判定できません。回路がpanel_size属性が見つかりません。SPAN Panel統合を更新してください。","editor.panel_label":"SPAN Panel","editor.select_panel":"パネルを選択...","editor.chart_window":"グラフ時間ウィンドウ","editor.days":"日","editor.hours":"時間","editor.minutes":"分","editor.chart_metric":"グラフ指標","editor.visible_sections":"表示セクション","editor.panel_circuits":"パネル回路","editor.battery_bess":"バッテリー (BESS)","editor.ev_charger_evse":"EV充電器 (EVSE)","editor.tab_style":"タブスタイル","editor.tab_style_text":"テキスト","editor.tab_style_icon":"アイコン","metric.power":"電力","metric.current":"電流","metric.soc":"充電状態","metric.soe":"エネルギー状態","shedding.always_on":"重要","shedding.never":"切断不可","shedding.soc_threshold":"SoCしきい値","shedding.off_grid":"切断可能","shedding.unknown":"不明","shedding.select.never":"停電時もオンを維持","shedding.select.soc_threshold":"バッテリーしきい値までオン","shedding.select.off_grid":"停電時にオフ"},pt:{"tab.panel":"Painel","tab.by_panel":"Por Painel","tab.by_activity":"Por Atividade","tab.by_area":"Por Área","tab.monitoring":"Monitoramento","tab.settings":"Configurações","list.search_placeholder":"Pesquisar circuitos...","list.unassigned_area":"Não atribuído","list.no_results":"Nenhum circuito encontrado","monitoring.heading":"Monitoramento","monitoring.global_settings":"Configurações Globais","monitoring.enabled":"Ativado","monitoring.continuous":"Contínuo (%)","monitoring.spike":"Pico (%)","monitoring.window":"Janela (min)","monitoring.cooldown":"Resfriamento (min)","monitoring.monitored_points":"Pontos Monitorados","monitoring.col.name":"Nome","monitoring.col.continuous":"Contínuo","monitoring.col.spike":"Pico","monitoring.col.window":"Janela","monitoring.col.cooldown":"Resfriamento","monitoring.all_none":"Todos / Nenhum","monitoring.reset":"Redefinir","notification.heading":"Configurações de Notificação","notification.targets":"Destinos de Notificação","notification.none_selected":"Nenhum selecionado","notification.no_targets":"Nenhum destino de notificação encontrado","notification.all_targets":"Todos","notification.event_bus_target":"Barramento de Eventos (barramento de eventos do HA)","notification.priority":"Prioridade","notification.priority.default":"Padrão","notification.priority.passive":"Passivo","notification.priority.active":"Ativo","notification.priority.time_sensitive":"Urgente","notification.priority.critical":"Crítico","notification.hint.critical":"Substitui silencioso/Não perturbar","notification.hint.time_sensitive":"Atravessa o modo Foco","notification.hint.passive":"Entrega silenciosa","notification.hint.active":"Entrega padrão","notification.title_template":"Modelo de Título","notification.message_template":"Modelo de Mensagem","notification.placeholders":"Variáveis:","notification.event_bus_help":"O Barramento de Eventos dispara o tipo de evento","notification.event_bus_payload":"com dados:","notification.test_label":"Notificação de teste","notification.test_button":"Enviar teste","notification.test_sending":"Enviando...","notification.test_sent":"Notificação de teste enviada","error.prefix":"Erro:","error.failed_save":"Falha ao salvar","error.failed":"Falhou","settings.heading":"Configurações","settings.description":"As configurações gerais da integração (nomes de entidades, prefixo do dispositivo, números de circuito) são gerenciadas através do fluxo de opções da integração.","settings.open_link":"Abrir Configurações de Integração SPAN Panel","horizon.5m":"5 Minutes","horizon.1h":"1 Hour","horizon.1d":"1 Day","horizon.1w":"1 Week","horizon.1M":"1 Month","settings.graph_horizon_heading":"Graph Time Horizon","settings.graph_horizon_description":"Default time window for all circuit graphs. Individual circuits can override this in their settings panel.","settings.global_default":"Global Default","settings.default_scale":"Default Scale","settings.circuit_graph_scales":"Circuit Graph Scales","settings.col.circuit":"Circuit","settings.col.scale":"Scale","sidepanel.graph_horizon":"Graph Time Horizon","sidepanel.graph_horizon_failed":"Graph horizon update failed:","sidepanel.clear_graph_horizon_failed":"Clear graph horizon failed:","header.default_name":"SPAN Panel","header.monitoring_settings":"Configurações de monitoramento do painel","header.graph_settings":"Configurações do horizonte temporal do gráfico","header.site":"Local","header.grid":"Rede","header.upstream":"Montante","header.downstream":"Jusante","header.solar":"Solar","header.battery":"Bateria","header.toggle_units":"Alternar Watts / Amperes","header.enable_switches":"Ativar Interruptores","header.switches_enabled":"Interruptores Ativados","grid.unknown":"Desconhecido","grid.configure":"Configurar circuito","grid.configure_subdevice":"Configurar dispositivo","grid.on":"Lig","grid.off":"Des","subdevice.ev_charger":"Carregador VE","subdevice.battery":"Bateria","subdevice.fallback":"Sub-dispositivo","subdevice.soc":"SoC","subdevice.soe":"SoE","subdevice.power":"Potência","sidepanel.graph_settings":"Configurações de Gráficos","sidepanel.global_defaults":"Padrões globais para todos os circuitos","sidepanel.global_default":"Padrão Global","sidepanel.circuit_scales":"Escalas de Gráficos de Circuitos","sidepanel.subdevice_scales":"Escalas de Gráficos de Sub-Dispositivos","sidepanel.reset_to_global":"Redefinir para o padrão global","sidepanel.relay":"Relé","sidepanel.breaker":"Disjuntor","sidepanel.relay_failed":"Falha ao alternar relé:","sidepanel.shedding_priority":"Prioridade de Desligamento","sidepanel.priority_label":"Prioridade","sidepanel.shedding_failed":"Falha ao atualizar desligamento:","sidepanel.monitoring":"Monitoramento","sidepanel.global":"Global","sidepanel.custom":"Personalizado","sidepanel.continuous_pct":"Contínuo %","sidepanel.spike_pct":"Pico %","sidepanel.window_duration":"Duração da janela","sidepanel.cooldown":"Resfriamento","sidepanel.monitoring_toggle_failed":"Falha ao alternar monitoramento:","sidepanel.clear_monitoring_failed":"Falha ao limpar monitoramento:","sidepanel.save_threshold_failed":"Falha ao salvar limite:","sidepanel.favorite":"Favorito","sidepanel.save_to_favorites":"Salvar nos favoritos","sidepanel.favorite_failed":"Falha ao atualizar favorito:","panel.favorites":"Favoritos","panel.favorites_summary_one":"1 favorito","panel.favorites_summary_many":"{circuits} favoritos","status.monitoring":"Monitoramento","status.circuits":"circuitos","status.mains":"alimentação","status.warning":"aviso","status.warnings":"avisos","status.alert":"alerta","status.alerts":"alertas","status.override":"substituição","status.overrides":"substituições","card.no_device":"Abra o editor do cartão e selecione seu dispositivo SPAN Panel.","card.device_not_found":"Dispositivo do painel não encontrado. Verifique device_id na configuração do cartão.","card.loading":"Carregando...","card.topology_error":"A resposta de topologia não contém panel_size e nenhum circuito encontrado. Atualize a integração SPAN Panel.","card.panel_size_error":"Não foi possível determinar panel_size. Nenhum circuito encontrado e nenhum atributo panel_size. Atualize a integração SPAN Panel.","editor.panel_label":"SPAN Panel","editor.select_panel":"Selecione um painel...","editor.chart_window":"Janela de tempo do gráfico","editor.days":"dias","editor.hours":"horas","editor.minutes":"minutos","editor.chart_metric":"Métrica do gráfico","editor.visible_sections":"Seções visíveis","editor.panel_circuits":"Circuitos do painel","editor.battery_bess":"Bateria (BESS)","editor.ev_charger_evse":"Carregador VE (EVSE)","editor.tab_style":"Estilo das abas","editor.tab_style_text":"Texto","editor.tab_style_icon":"Ícone","metric.power":"Potência","metric.current":"Corrente","metric.soc":"Estado de Carga","metric.soe":"Estado de Energia","shedding.always_on":"Crítico","shedding.never":"Não desligável","shedding.soc_threshold":"Limite SoC","shedding.off_grid":"Desligável","shedding.unknown":"Desconhecido","shedding.select.never":"Permanece ligado em uma queda","shedding.select.soc_threshold":"Ligado até limite da bateria","shedding.select.off_grid":"Desliga em uma queda"}};function n(n){return t[e]?.[n]??t.en?.[n]??n}const i="power",s="5m",o={"5m":{ms:3e5,refreshMs:1e3,useRealtime:!0},"1h":{ms:36e5,refreshMs:3e4,useRealtime:!1},"1d":{ms:864e5,refreshMs:6e4,useRealtime:!1},"1w":{ms:6048e5,refreshMs:6e4,useRealtime:!1},"1M":{ms:2592e6,refreshMs:6e4,useRealtime:!1}},a="span_panel",r="CLOSED",l="pv",c="bess",d="evse",h="sub_",p=500,u={power:{entityRole:"power",label:()=>n("metric.power"),unit:e=>Math.abs(e)>=1e3?"kW":"W",format:e=>{const t=Math.abs(e);return t>=1e3?(t/1e3).toFixed(1):t<10&&t>0?t.toFixed(1):String(Math.round(t))}},current:{entityRole:"current",label:()=>n("metric.current"),unit:()=>"A",format:e=>Math.abs(e).toFixed(1)}},g={soc:{entityRole:"soc",label:()=>n("metric.soc"),unit:()=>"%",format:e=>String(Math.round(e)),fixedMin:0,fixedMax:100},soe:{entityRole:"soe",label:()=>n("metric.soe"),unit:()=>"kWh",format:e=>e.toFixed(1)},power:u.power},_={always_on:{icon:"mdi:battery",icon2:"mdi:router-wireless",color:"#4caf50",label:()=>n("shedding.always_on")},never:{icon:"mdi:battery",color:"#4caf50",label:()=>n("shedding.never")},soc_threshold:{icon:"mdi:battery-alert-variant-outline",color:"#9c27b0",label:()=>n("shedding.soc_threshold"),textLabel:"SoC"},off_grid:{icon:"mdi:transmission-tower",color:"#ff9800",label:()=>n("shedding.off_grid")},unknown:{icon:"mdi:help-circle-outline",color:"#888",label:()=>n("shedding.unknown")}},f="#ff9800";function v(e,t,n,i){var s,o=arguments.length,a=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,n,i);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(o<3?s(a):o>3?s(t,n,a):s(t,n))||a);return o>3&&a&&Object.defineProperty(t,n,a),a}"function"==typeof SuppressedError&&SuppressedError; /** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const m=globalThis,b=m.ShadowRoot&&(void 0===m.ShadyCSS||m.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,y=Symbol(),w=new WeakMap;let x=class{constructor(e,t,i){if(this._$cssResult$=!0,i!==y)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(b&&void 0===e){const i=void 0!==t&&1===t.length;i&&(e=w.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),i&&w.set(t,e))}return e}toString(){return this.cssText}};const $=b?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new x("string"==typeof e?e:e+"",void 0,y))(t)})(e):e,{is:S,defineProperty:C,getOwnPropertyDescriptor:E,getOwnPropertyNames:k,getOwnPropertySymbols:z,getPrototypeOf:A}=Object,P=globalThis,M=P.trustedTypes,T=M?M.emptyScript:"",I=P.reactiveElementPolyfillSupport,D=(e,t)=>e,N={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},L=(e,t)=>!S(e,t),H={attribute:!0,type:String,converter:N,reflect:!1,useDefault:!1,hasChanged:L}; +const m=globalThis,b=m.ShadowRoot&&(void 0===m.ShadyCSS||m.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,y=Symbol(),w=new WeakMap;let x=class{constructor(e,t,n){if(this._$cssResult$=!0,n!==y)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const t=this.t;if(b&&void 0===e){const n=void 0!==t&&1===t.length;n&&(e=w.get(t)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),n&&w.set(t,e))}return e}toString(){return this.cssText}};const $=b?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const n of e.cssRules)t+=n.cssText;return(e=>new x("string"==typeof e?e:e+"",void 0,y))(t)})(e):e,{is:S,defineProperty:C,getOwnPropertyDescriptor:E,getOwnPropertyNames:k,getOwnPropertySymbols:z,getPrototypeOf:A}=Object,P=globalThis,M=P.trustedTypes,T=M?M.emptyScript:"",I=P.reactiveElementPolyfillSupport,D=(e,t)=>e,N={toAttribute(e,t){switch(t){case Boolean:e=e?T:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let n=e;switch(t){case Boolean:n=null!==e;break;case Number:n=null===e?null:Number(e);break;case Object:case Array:try{n=JSON.parse(e)}catch(e){n=null}}return n}},L=(e,t)=>!S(e,t),H={attribute:!0,type:String,converter:N,reflect:!1,useDefault:!1,hasChanged:L}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */Symbol.metadata??=Symbol("metadata"),P.litPropertyMetadata??=new WeakMap;let F=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=H){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(e,i,t);void 0!==n&&C(this.prototype,e,n)}}static getPropertyDescriptor(e,t,i){const{get:n,set:s}=E(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:n,set(t){const o=n?.call(this);s?.call(this,t),this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??H}static _$Ei(){if(this.hasOwnProperty(D("elementProperties")))return;const e=A(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(D("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(D("properties"))){const e=this.properties,t=[...k(e),...z(e)];for(const i of t)this.createProperty(i,e[i])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,i]of t)this.elementProperties.set(e,i)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const i=this._$Eu(e,t);void 0!==i&&this._$Eh.set(i,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const i of t.keys())this.hasOwnProperty(i)&&(e.set(i,this[i]),delete this[i]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(b)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const i of t){const t=document.createElement("style"),n=m.litNonce;void 0!==n&&t.setAttribute("nonce",n),t.textContent=i.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$ET(e,t){const i=this.constructor.elementProperties.get(e),n=this.constructor._$Eu(e,i);if(void 0!==n&&!0===i.reflect){const s=(void 0!==i.converter?.toAttribute?i.converter:N).toAttribute(t,i.type);this._$Em=e,null==s?this.removeAttribute(n):this.setAttribute(n,s),this._$Em=null}}_$AK(e,t){const i=this.constructor,n=i._$Eh.get(e);if(void 0!==n&&this._$Em!==n){const e=i.getPropertyOptions(n),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:N;this._$Em=n;const o=s.fromAttribute(t,e.type);this[n]=o??this._$Ej?.get(n)??o,this._$Em=null}}requestUpdate(e,t,i,n=!1,s){if(void 0!==e){const o=this.constructor;if(!1===n&&(s=this[e]),i??=o.getPropertyOptions(e),!((i.hasChanged??L)(s,t)||i.useDefault&&i.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,i))))return;this.C(e,t,i)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:i,reflect:n,wrapped:s},o){i&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||i||(t=void 0),this._$AL.set(e,t)),!0===n&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,i]of e){const{wrapped:e}=i,n=this[t];!0!==e||this._$AL.has(t)||void 0===n||this.C(t,void 0,i,n)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};F.elementStyles=[],F.shadowRootOptions={mode:"open"},F[D("elementProperties")]=new Map,F[D("finalized")]=new Map,I?.({ReactiveElement:F}),(P.reactiveElementVersions??=[]).push("2.1.2"); + */Symbol.metadata??=Symbol("metadata"),P.litPropertyMetadata??=new WeakMap;let F=class extends HTMLElement{static addInitializer(e){this._$Ei(),(this.l??=[]).push(e)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(e,t=H){if(t.state&&(t.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(e)&&((t=Object.create(t)).wrapped=!0),this.elementProperties.set(e,t),!t.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(e,n,t);void 0!==i&&C(this.prototype,e,i)}}static getPropertyDescriptor(e,t,n){const{get:i,set:s}=E(this.prototype,e)??{get(){return this[t]},set(e){this[t]=e}};return{get:i,set(t){const o=i?.call(this);s?.call(this,t),this.requestUpdate(e,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)??H}static _$Ei(){if(this.hasOwnProperty(D("elementProperties")))return;const e=A(this);e.finalize(),void 0!==e.l&&(this.l=[...e.l]),this.elementProperties=new Map(e.elementProperties)}static finalize(){if(this.hasOwnProperty(D("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(D("properties"))){const e=this.properties,t=[...k(e),...z(e)];for(const n of t)this.createProperty(n,e[n])}const e=this[Symbol.metadata];if(null!==e){const t=litPropertyMetadata.get(e);if(void 0!==t)for(const[e,n]of t)this.elementProperties.set(e,n)}this._$Eh=new Map;for(const[e,t]of this.elementProperties){const n=this._$Eu(e,t);void 0!==n&&this._$Eh.set(n,e)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const n=new Set(e.flat(1/0).reverse());for(const e of n)t.unshift($(e))}else void 0!==e&&t.push($(e));return t}static _$Eu(e,t){const n=t.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof e?e.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(e=>this.enableUpdating=e),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(e=>e(this))}addController(e){(this._$EO??=new Set).add(e),void 0!==this.renderRoot&&this.isConnected&&e.hostConnected?.()}removeController(e){this._$EO?.delete(e)}_$E_(){const e=new Map,t=this.constructor.elementProperties;for(const n of t.keys())this.hasOwnProperty(n)&&(e.set(n,this[n]),delete this[n]);e.size>0&&(this._$Ep=e)}createRenderRoot(){const e=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return((e,t)=>{if(b)e.adoptedStyleSheets=t.map(e=>e instanceof CSSStyleSheet?e:e.styleSheet);else for(const n of t){const t=document.createElement("style"),i=m.litNonce;void 0!==i&&t.setAttribute("nonce",i),t.textContent=n.cssText,e.appendChild(t)}})(e,this.constructor.elementStyles),e}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(e=>e.hostConnected?.())}enableUpdating(e){}disconnectedCallback(){this._$EO?.forEach(e=>e.hostDisconnected?.())}attributeChangedCallback(e,t,n){this._$AK(e,n)}_$ET(e,t){const n=this.constructor.elementProperties.get(e),i=this.constructor._$Eu(e,n);if(void 0!==i&&!0===n.reflect){const s=(void 0!==n.converter?.toAttribute?n.converter:N).toAttribute(t,n.type);this._$Em=e,null==s?this.removeAttribute(i):this.setAttribute(i,s),this._$Em=null}}_$AK(e,t){const n=this.constructor,i=n._$Eh.get(e);if(void 0!==i&&this._$Em!==i){const e=n.getPropertyOptions(i),s="function"==typeof e.converter?{fromAttribute:e.converter}:void 0!==e.converter?.fromAttribute?e.converter:N;this._$Em=i;const o=s.fromAttribute(t,e.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(e,t,n,i=!1,s){if(void 0!==e){const o=this.constructor;if(!1===i&&(s=this[e]),n??=o.getPropertyOptions(e),!((n.hasChanged??L)(s,t)||n.useDefault&&n.reflect&&s===this._$Ej?.get(e)&&!this.hasAttribute(o._$Eu(e,n))))return;this.C(e,t,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(e,t,{useDefault:n,reflect:i,wrapped:s},o){n&&!(this._$Ej??=new Map).has(e)&&(this._$Ej.set(e,o??t??this[e]),!0!==s||void 0!==o)||(this._$AL.has(e)||(this.hasUpdated||n||(t=void 0),this._$AL.set(e,t)),!0===i&&this._$Em!==e&&(this._$Eq??=new Set).add(e))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[e,t]of this._$Ep)this[e]=t;this._$Ep=void 0}const e=this.constructor.elementProperties;if(e.size>0)for(const[t,n]of e){const{wrapped:e}=n,i=this[t];!0!==e||this._$AL.has(t)||void 0===i||this.C(t,void 0,n,i)}}let e=!1;const t=this._$AL;try{e=this.shouldUpdate(t),e?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM()}catch(t){throw e=!1,this._$EM(),t}e&&this._$AE(t)}willUpdate(e){}_$AE(e){this._$EO?.forEach(e=>e.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(e){return!0}update(e){this._$Eq&&=this._$Eq.forEach(e=>this._$ET(e,this[e])),this._$EM()}updated(e){}firstUpdated(e){}};F.elementStyles=[],F.shadowRootOptions={mode:"open"},F[D("elementProperties")]=new Map,F[D("finalized")]=new Map,I?.({ReactiveElement:F}),(P.reactiveElementVersions??=[]).push("2.1.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const R=globalThis,O=e=>e,q=R.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ie=/'/g,ne=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...i)=>({_$litType$:e,strings:t,values:i}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const i=e.length-1,n=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ne:ie):a===ne||a===ie?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?i+W:c>=0?(n.push(r),i.slice(0,c)+U+i.slice(c)+G+h):i+G+(-2===c?t:h)}return[de(e,o+(e[i]||"")+(2===t?"":3===t?"":"")),n]};class pe{constructor({strings:e,_$litType$:t},i){let n;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,i),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(n=ce.nextNode())&&r.length0){n.textContent=q?q.emptyScript:"";for(let i=0;iX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:i}=e,n="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=pe.createElement(de(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(t);else{const e=new ge(n,this),i=e.u(this.options);e.p(t),this.T(i),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,n=0;for(const s of e)n===t.length?t.push(i=new _e(this.O(Q()),this.O(Q()),this,this.options)):i=t[n],i._$AI(s),n++;n2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=re}_$AI(e,t=this,i,n){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const n=e;let a,r;for(e=s[0],a=0;ae,q=R.trustedTypes,j=q?q.createPolicy("lit-html",{createHTML:e=>e}):void 0,U="$lit$",G=`lit$${Math.random().toFixed(9).slice(2)}$`,V="?"+G,W=`<${V}>`,B=document,Q=()=>B.createComment(""),J=e=>null===e||"object"!=typeof e&&"function"!=typeof e,X=Array.isArray,K="[ \t\n\f\r]",Z=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Y=/-->/g,ee=/>/g,te=RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),ne=/'/g,ie=/"/g,se=/^(?:script|style|textarea|title)$/i,oe=(e=>(t,...n)=>({_$litType$:e,strings:t,values:n}))(1),ae=Symbol.for("lit-noChange"),re=Symbol.for("lit-nothing"),le=new WeakMap,ce=B.createTreeWalker(B,129);function de(e,t){if(!X(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==j?j.createHTML(t):t}const he=(e,t)=>{const n=e.length-1,i=[];let s,o=2===t?"":3===t?"":"",a=Z;for(let t=0;t"===l[0]?(a=s??Z,c=-1):void 0===l[1]?c=-2:(c=a.lastIndex-l[2].length,r=l[1],a=void 0===l[3]?te:'"'===l[3]?ie:ne):a===ie||a===ne?a=te:a===Y||a===ee?a=Z:(a=te,s=void 0);const h=a===te&&e[t+1].startsWith("/>")?" ":"";o+=a===Z?n+W:c>=0?(i.push(r),n.slice(0,c)+U+n.slice(c)+G+h):n+G+(-2===c?t:h)}return[de(e,o+(e[n]||"")+(2===t?"":3===t?"":"")),i]};class pe{constructor({strings:e,_$litType$:t},n){let i;this.parts=[];let s=0,o=0;const a=e.length-1,r=this.parts,[l,c]=he(e,t);if(this.el=pe.createElement(l,n),ce.currentNode=this.el.content,2===t||3===t){const e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;null!==(i=ce.nextNode())&&r.length0){i.textContent=q?q.emptyScript:"";for(let n=0;nX(e)||"function"==typeof e?.[Symbol.iterator])(e)?this.k(e):this._(e)}O(e){return this._$AA.parentNode.insertBefore(e,this._$AB)}T(e){this._$AH!==e&&(this._$AR(),this._$AH=this.O(e))}_(e){this._$AH!==re&&J(this._$AH)?this._$AA.nextSibling.data=e:this.T(B.createTextNode(e)),this._$AH=e}$(e){const{values:t,_$litType$:n}=e,i="number"==typeof n?this._$AC(e):(void 0===n.el&&(n.el=pe.createElement(de(n.h,n.h[0]),this.options)),n);if(this._$AH?._$AD===i)this._$AH.p(t);else{const e=new ge(i,this),n=e.u(this.options);e.p(t),this.T(n),this._$AH=e}}_$AC(e){let t=le.get(e.strings);return void 0===t&&le.set(e.strings,t=new pe(e)),t}k(e){X(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let n,i=0;for(const s of e)i===t.length?t.push(n=new _e(this.O(Q()),this.O(Q()),this,this.options)):n=t[i],n._$AI(s),i++;i2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=re}_$AI(e,t=this,n,i){const s=this.strings;let o=!1;if(void 0===s)e=ue(this,e,t,0),o=!J(e)||e!==this._$AH&&e!==ae,o&&(this._$AH=e);else{const i=e;let a,r;for(e=s[0],a=0;a{const n=i?.renderBefore??t;let s=n._$litPart$;if(void 0===s){const e=i?.renderBefore??null;n._$litPart$=s=new _e(t.insertBefore(Q(),e),e,void 0,i??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ae}};$e._$litElement$=!0,$e.finalized=!0,xe.litElementHydrateSupport?.({LitElement:$e});const Se=xe.litElementPolyfillSupport;Se?.({LitElement:$e}),(xe.litElementVersions??=[]).push("4.2.2"); + */let $e=class extends F{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const e=super.createRenderRoot();return this.renderOptions.renderBefore??=e.firstChild,e}update(e){const t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(e),this._$Do=((e,t,n)=>{const i=n?.renderBefore??t;let s=i._$litPart$;if(void 0===s){const e=n?.renderBefore??null;i._$litPart$=s=new _e(t.insertBefore(Q(),e),e,void 0,n??{})}return s._$AI(e),s})(t,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return ae}};$e._$litElement$=!0,$e.finalized=!0,xe.litElementHydrateSupport?.({LitElement:$e});const Se=xe.litElementPolyfillSupport;Se?.({LitElement:$e}),(xe.litElementVersions??=[]).push("4.2.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce,t,i)=>{const{kind:n,metadata:s}=i;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===n&&((e=Object.create(e)).wrapped=!0),o.set(i.name,e),"accessor"===n){const{name:n}=i;return{set(i){const s=t.get.call(this);t.set.call(this,i),this.requestUpdate(n,s,e,!0,i)},init(t){return void 0!==t&&this.C(n,void 0,e,t),t}}}if("setter"===n){const{name:n}=i;return function(i){const s=this[n];t.call(this,i),this.requestUpdate(n,s,e,!0,i)}}throw Error("Unsupported decorator location: "+n)}; +const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce,t,n)=>{const{kind:i,metadata:s}=n;let o=globalThis.litPropertyMetadata.get(s);if(void 0===o&&globalThis.litPropertyMetadata.set(s,o=new Map),"setter"===i&&((e=Object.create(e)).wrapped=!0),o.set(n.name,e),"accessor"===i){const{name:i}=n;return{set(n){const s=t.get.call(this);t.set.call(this,n),this.requestUpdate(i,s,e,!0,n)},init(t){return void 0!==t&&this.C(i,void 0,e,t),t}}}if("setter"===i){const{name:i}=n;return function(n){const s=this[i];t.call(this,n),this.requestUpdate(i,s,e,!0,n)}}throw Error("Unsupported decorator location: "+i)}; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */function ke(e){return(t,i)=>"object"==typeof i?Ee(e,t,i):((e,t,i)=>{const n=t.hasOwnProperty(i);return t.constructor.createProperty(i,e),n?Object.getOwnPropertyDescriptor(t,i):void 0})(e,t,i)} + */function ke(e){return(t,n)=>"object"==typeof n?Ee(e,t,n):((e,t,n)=>{const i=t.hasOwnProperty(n);return t.constructor.createProperty(n,e),i?Object.getOwnPropertyDescriptor(t,n):void 0})(e,t,n)} /** * @license * Copyright 2017 Google LLC @@ -41,12 +41,12 @@ const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */const Ae=2;class Pe{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}} + */const Ae=2;class Pe{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,n){this._$Ct=e,this._$AM=t,this._$Ci=n}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}} /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function De(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const Ne="favorites-changed";async function Le(e,t,i={}){const n=await e.callWS({type:"call_service",domain:a,service:t,service_data:i,return_response:!0});return n?.response??null}class He{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Fe(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const Re=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);class Oe extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const i=document.createElement("style");i.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(i);const n=document.createElement("div");n.className="backdrop",n.addEventListener("click",()=>this.close()),t.appendChild(n);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,n=this._createHeader(i("sidepanel.graph_settings"),i("sidepanel.global_defaults"));e.appendChild(n);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=i("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=i("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const n=document.createElement("div");n.className="section-label",n.textContent=i("sidepanel.circuit_scales"),e.appendChild(n);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[n,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||n,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(n)??!1);e&&s.appendChild(e)}const l=h[n]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=n;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${n}`,p,()=>{const e={circuit_id:n,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=i("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const i={circuit_id:n};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const n=document.createElement("div");n.className="section-label",n.textContent=i("sidepanel.subdevice_scales"),e.appendChild(n);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[n,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||n,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(n)??!1);e&&s.appendChild(e)}const l=m[n]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=n;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const n=`horizon.${e}`,s=i(n);t.textContent=s!==n?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${n}`,p,()=>{const e={subdevice_id:n,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=i("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const i={subdevice_id:n};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const i=`${De(String(t.breaker_rating_a))}A · ${De(String(t.voltage))}V · Tabs [${De(String(t.tabs))}]`,n=this._createHeader(De(t.name),i);e.appendChild(n);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[i,n]of Object.entries(e)){if("sensor"===n.domain)return i;t||(t=i)}return t}_buildSubDeviceFavoriteHeart(e,t){const i=this._subDeviceFavoriteEntityId(e);return i?this._buildHeartButton(i,t):null}_buildFavoriteHeart(e,t){const i=this._favoriteEntityId(e);return i?this._buildHeartButton(i,t):(console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"),null)}_buildHeartButton(e,t){const n=document.createElement("button");n.type="button",n.className=t?"fav-heart active":"fav-heart",n.dataset.role="fav-heart",n.title=i("sidepanel.save_to_favorites"),n.setAttribute("role","switch"),n.setAttribute("aria-pressed",String(t)),n.setAttribute("aria-label",i("sidepanel.save_to_favorites"));const s=document.createElement("ha-icon");return s.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),n.appendChild(s),n.addEventListener("click",t=>{t.stopPropagation(),this._toggleFavoriteEntity(n,s,e).catch(()=>{})}),n}async _toggleFavoriteEntity(e,t,n){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(o));try{o?await async function(e,t){const i=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Ne)),i?.favorites??{}}(this._hass,n):await async function(e,t){const i=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Ne)),i?.favorites??{}}(this._hass,n)}catch(n){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(s));const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(n);throw this._showError(`${i("sidepanel.favorite_failed")} ${o}`),n}}_renderFavoriteSection(e,t){const i=this._favoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,n){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=i("sidepanel.save_to_favorites"),o.appendChild(a),o.appendChild(this._buildHeartButton(t,n)),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const i=this._createHeader(De(t.name),De(t.deviceType));e.appendChild(i);const n=document.createElement("div");n.className="panel-body",e.appendChild(n);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",n.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(n,t),this._renderSubDeviceHorizonSection(n,t)}_renderSubDeviceFavoriteSection(e,t){const i=this._subDeviceFavoriteEntityId(t.entities);i&&this._appendFavoriteHeartSection(e,i,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const n=document.createElement("div");n.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=i("sidepanel.graph_horizon"),n.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:i("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:n}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=n,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const n={subdevice_id:t.subDeviceId};t.configEntryId&&(n.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...n,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}n.appendChild(h),e.appendChild(n)}_createHeader(e,t){const i=document.createElement("div");i.className="panel-header";const n=document.createElement("div"),s=De(e),o=De(t);n.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),i.appendChild(n),i.appendChild(a),i}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const n=document.createElement("div");n.className="section",n.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=i("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${i("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),n.appendChild(s),e.appendChild(n)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const n=document.createElement("div");n.className="section",n.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=i("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of Re){const t=_[e];if(!t)continue;const n=document.createElement("option");n.value=e,n.textContent=i(`shedding.select.${e}`)||t.label(),e===l&&(n.selected=!0),a.appendChild(n)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${i("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),n.appendChild(s),e.appendChild(n)}_renderGraphHorizonSection(e,t){const n=document.createElement("div");n.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=i("sidepanel.graph_horizon"),n.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:i("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const i=t.dataset.horizon;t.classList.toggle("active",i===e),t.classList.toggle("referenced","global"===e&&i===d)}};for(const{key:e,label:n}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=n,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const n={circuit_id:t.uuid};t.configEntryId&&(n.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...n,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${i("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}n.appendChild(h),e.appendChild(n)}_renderMonitoringSection(e,t){const n=document.createElement("div");n.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=i("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),n.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",n.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(i("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(i("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(i("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(i("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const n={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",n).catch(e=>this._showError(`${i("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const n="custom"===e.value&&e.checked;if(p.style.display=n?"block":"none",!n&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${i("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(n)}_createThresholdRow(e,t,n,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(n),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),n=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:n?Number(n.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${i("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,n,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(n),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),n=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:n?Number(n.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${i("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const i=this._hass?.states?.[e.entities.switch]?.state;"on"===i?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const i=this._hass?.states?.[e.entities.select]?.state||"";t.value=i}}}}_callService(e,t,i){return this._hass?Promise.resolve(this._hass.callService(e,t,i)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,i){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],i()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Oe)}catch{}async function qe(e,t){const[i,n,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of i)o.set(e.area_id,e.name);const a=new Map;for(const e of n)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const i of Object.values(e.entities)){if(!i)continue;const e=a.get(i);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function je(e,t){if(!t)throw new Error(i("card.device_not_found"));const n=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=n.panel_size??function(e){let t=0;for(const i of Object.values(e))if(i)for(const e of i.tabs)e>t&&(t=e);return t>0?t+t%2:0}(n.circuits);if(!s)throw new Error(i("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await qe(e,n),{topology:n,panelDevice:r,panelSize:s}}function Ue(e,t,n={}){const s=De(e.device_name||i("header.default_name")),o=De(e.serial||""),a=De(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==n.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${i("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${i("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${i("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${i("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${i("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${i("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${i("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Ge=u.power;function Ve(e){return Ge.unit(e)}function We(e){return(e<0?"-":"")+Ge.format(e)}function Be(e){return(Math.abs(e)/1e3).toFixed(1)}function Qe(e){return Math.ceil(e/2)}function Je(e){return e%2==0?1:0}function Xe(e){if(2!==e.length)return null;const[t,i]=[Math.min(...e),Math.max(...e)];return Qe(t)===Qe(i)?"row-span":Je(t)===Je(i)?"col-span":"row-span"}function Ke(e){const t=e.chart_metric??n;return u[t]??u[n]}function Ze(e,t){const i=function(e){return Ke(e).entityRole}(t);return e.entities?.[i]??e.entities?.power??null}class Ye{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._status;if(this._status&&i-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:n,return_response:!0});this._status=s?.response??null,this._lastFetch=i}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function et(e,t){return e?.circuits?e.circuits[t]??null:null}function tt(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function it(e,t,n,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=De(t.name||i("grid.unknown")),C=Ke(c);let E;if("current"===C.entityRole){const e=t.entities?.current,i=e?a.states[e]:null,n=i&&parseFloat(i.state)||0;E=`${C.format(n)}A`}else E=`${We(v)}${Ve(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${i(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function nt(e,t){return`\n
\n \n
\n `}const st={names:["power","battery power"],suffixes:["_power"]},ot={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},at={names:["state of energy"],suffixes:["_soe_kwh"]},rt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function lt(e,t){if(!e.entities)return null;for(const[i,n]of Object.entries(e.entities)){if("sensor"!==n.domain)continue;const e=(n.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return i;if(n.unique_id&&t.suffixes.some(e=>n.unique_id.endsWith(e)))return i}return null}function ct(e){return lt(e,st)}function dt(e){return lt(e,ot)}function ht(e){return lt(e,at)}function pt(e){return lt(e,rt)}function ut(e,t,n){const s=!1!==n.show_battery,o=!1!==n.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?i("subdevice.ev_charger"):s.type===c?i("subdevice.battery"):i("subdevice.fallback"),a=ct(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?dt(s):null,v=g?ht(s):null,m=g?pt(s):null,b=gt(s,t,n,new Set([a,f,v,m].filter(e=>null!==e))),y=_t(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${De(o)}\n ${De(s.name||"")}\n ${a?`${We(u)} ${Ve(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function gt(e,t,i,n){const s=i.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[i,a]of Object.entries(e.entities)){if(n.has(i))continue;if(!0!==s[i])continue;const r=t.states[i];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||i;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${De(l)}:\n ${De(d)}\n
\n `}return o}function _t(e,t,n,s,o,a){if(n){const t=[{key:`${h}${e}_soc`,title:i("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:i("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:i("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${De(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ft(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,i=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(i,6e4)}function vt(e){const t=o[e];return t?t.ms:o[s].ms}function mt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function bt(e){return Math.max(500,Math.floor(e/5e3))}function yt(e,t,i,n,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:n,value:i});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function wt(e,t,i=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const n=[e[0]];for(let t=1;t=i&&n.push(e[t]);return n.length>t&&n.splice(0,n.length-t),n}async function xt(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=n/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const i=e.start;i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(n,t)}}}async function $t(e,t,i,n,s){const o=new Date(Date.now()-n).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=mt(n),l=bt(n);for(const[e,t]of Object.entries(a)){const n=i.get(e);if(!n||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const i=1e3*(e.lu||e.lc||0);i>0&&o.push({time:i,value:t})}if(o.length>0){const e=s.get(n)||[],t=[...o,...e];s.set(n,wt(t,r,l))}}}function St(e){if(!e.sub_devices)return[];const t=[];for(const[i,n]of Object.entries(e.sub_devices)){const e={power:ct(n)};n.type===c&&(e.soc=dt(n),e.soe=ht(n));for(const[n,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${i}_${n}`,devId:i})}return t}async function Ct(e,t,i,n,s,o){if(!t||!e)return;const a=new Map;for(const[e,n]of Object.entries(t.circuits)){const t=Ze(n,i);if(!t)continue;let o;o=s&&s.has(e)?vt(s.get(e)):ft(i),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:n,devId:s}of St(t)){let t;t=o&&o.has(s)?vt(o.get(s)):ft(i),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,n)}const r=[];for(const[t,i]of a){if(0===i.entityIds.length)continue;t>2592e5?r.push(xt(e,i.entityIds,i.uuidByEntity,t,n)):r.push($t(e,i.entityIds,i.uuidByEntity,t,n))}await Promise.all(r)}function Et(e,t,i,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,i,s,o,a=!1){i||(i=u[n]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==i.fixedMin&&void 0!==i.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const i of e)i[1]>t&&(t=i[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>i.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=i.fixedMin,f.max=i.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===i.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],n=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${n}
${i.format(s)} ${i.unit(s)}
`}},animation:!1};return{options:v,series:g}}(i,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function kt(e,t,n,s,o,a){if(!e||!n||!t)return;const c=ft(s);let d=0;for(const[,e]of Object.entries(n.circuits)){const i=e.entities?.power;if(!i)continue;const n=t.states[i],s=n&&parseFloat(n.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,i,n,s){const o="current"===(n.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=i.panel_entities?.site_power,n=e?t.states[e]:null,s=n?parseFloat(n.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=i.panel_entities?.site_power;if(e){const i=t.states[e];i&&(s=Math.abs(parseFloat(i.state)||0))}a&&(a.textContent=Be(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=i.panel_entities?.current_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;l.textContent=Be(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=i.panel_entities?.feedthrough_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=n?Math.abs(parseFloat(n.state)||0):0;d.textContent=Be(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=i.panel_entities?.pv_power,n=e?t.states[e]:null;if(o){const e=n?parseFloat(n.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(n){const e=Math.abs(parseFloat(n.state)||0);p.textContent=Be(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=i.panel_entities?.battery_level,n=e?t.states[e]:null;n&&(g.textContent=`${Math.round(parseFloat(n.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=i.panel_entities?.dsm_state,n=e?t.states[e]:null;_.textContent=n?t.formatEntityState?.(n)||n.state:"--"}}(e,t,n,s,d);const h=Ke(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(n.circuits)){const n=e.querySelector(`[data-uuid="${s}"]`);if(!n)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=n.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;w.innerHTML=`${h.format(n)}A`}else w.innerHTML=`${We(f)}${Ve(f)}`;const x=n.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=i(y?"grid.on":"grid.off"))}let $;if(n.classList.toggle("circuit-off",!y),n.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,i=e?t.states[e]:null;$=i?i.state:"unknown"}const S=_[$]??_.unknown,C=n.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=n.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=n.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=n.querySelector(".chart-container");if(z){const e=o.get(s)||[],i=n.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?vt(a.get(s)):c,p=d.device_type===l;Et(z,t,e,r,h,v,i,d.breaker_rating_a??void 0,p)}}}class zt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const i=Date.now();if(this._fetching)return this._settings;if(this._settings&&i-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const n={};t&&(n.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:n,return_response:!0});this._settings=s?.response??null,this._lastFetch=i}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function At(e,t){if(!e)return s;const i=e.circuits?.[t];return i?.has_override?i.horizon:e.global_horizon??s}function Pt(e,t){if(!e)return s;const i=e.sub_devices?.[t];return i?.has_override?i.horizon:e.global_horizon??s}class Mt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ye,this.graphSettingsCache=new zt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,i,n){this._topology=e,this._config=t,this._hass=i,this._configEntryId=n}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,At(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,Pt(e,t))}async fetchAndBuildHorizonMaps(){try{this._favRefs?await this._buildFavoritesHorizonMaps():(await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings))}catch{}}async _buildFavoritesHorizonMaps(){if(!this._hass||!this._favRefs||!this._topology)return;const e=new Set;for(const t of Object.values(this._favRefs))t.configEntryId&&e.add(t.configEntryId);const t=new Map;await Promise.all(Array.from(e).map(async e=>{t.set(e,await this._fetchGraphSettingsFresh(e))})),this.horizonMap.clear(),this.subDeviceHorizonMap.clear();for(const e of Object.keys(this._topology.circuits)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.horizonMap.set(e,At(n,s))}if(this._topology.sub_devices)for(const e of Object.keys(this._topology.sub_devices)){const i=this._favRefs[e],n=i?.configEntryId?t.get(i.configEntryId)??null:null,s=i?.targetId??e;this.subDeviceHorizonMap.set(e,Pt(n,s))}}async loadHistory(){await Ct(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,i]of Object.entries(this._topology.circuits)){const n=this.horizonMap.get(t)??s;if(!o[n]?.useRealtime)continue;const a=Ze(i,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=vt(n),d=mt(c),h=bt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of St(this._topology))i.has(t)&&n.add(e);const s=new Map;try{await Ct(this._hass,this._topology,this._config,s,t,i);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of n){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(kt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,i,n,s,o){if(!i.sub_devices)return;const a=ft(n);for(const[n,r]of Object.entries(i.sub_devices)){const i=e.querySelector(`[data-subdev="${n}"]`);if(!i)continue;const l=ct(r);if(l){const e=t.states[l],n=e&&parseFloat(e.state)||0,s=i.querySelector(".sub-power-value");s&&(s.innerHTML=`${We(n)} ${Ve(n)}`)}const c=i.querySelectorAll("[data-chart-key]");for(const e of c){const i=e.dataset.chartKey;if(!i)continue;const r=s.get(i)||[];let l=g.power;i.endsWith("_soc")?l=g.soc:i.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");Et(e,t,r,o?.has(n)?vt(o.get(n)):a,l,!1,c?120:150,void 0,i.endsWith("_soc")||i.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const n=i.querySelector(`[data-eid="${e}"]`);if(!n)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}n.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this._favRefs?await this._buildFavoritesHorizonMaps():(this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const i=e.target,n=i?.closest(".toggle-pill");if(!n)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=n.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const i=e.target,n=i?.closest(".gear-icon");if(!n)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,n.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=n.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,i=t&&"circuit"===t.kind?t.targetId:a,n=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(n),this._fetchMonitoringStatusFresh(n)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,n),this.monitoringCache.fetch(this._hass,n)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[i],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(i)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:i,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:n})}}const r=n.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,i=t&&"sub_device"===t.kind?t.targetId:r,n=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(n):(await this.graphSettingsCache.fetch(this._hass,n),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[i],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(i)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:i,name:e.name??i,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:n})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return i?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const i=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),n=i?.response;return n?{circuits:n.circuits,mains:n.mains}:null}catch{return null}}bindSlideConfirm(e,t){const i=e.querySelector(".slide-confirm-knob"),n=e.querySelector(".slide-confirm-text");if(!i||!n)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-i.offsetLeft,a=e.offsetWidth-i.offsetWidth-4,i.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));i.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(i.offsetLeft-2)/a>=.9?(i.style.left=a+"px",e.classList.add("confirmed"),i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),n.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(i.classList.add("snapping"),i.style.left="2px")};i.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),i.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),i.classList.add("snapping"),i.style.left="2px",i.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),n.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const i=t[0];if(!i)return;const n=i.contentRect.width;Math.abs(n-this._lastWidth)<5||(this._lastWidth=n,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Tt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class It{constructor(){this._ctrl=new Mt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,n,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await je(t,n);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${De(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=Ue(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),n=Object.values(e.mains??{}),s=[...t,...n],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${i("status.monitoring")} · ${t.length} ${i("status.circuits")} · ${n.length} ${i("status.mains")}\n \n ${o>0?`${o} ${i(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${i(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${i(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,i,n,s){const o=new Map,a=new Set;for(const[t,i]of Object.entries(e.circuits)){const e=i.tabs;if(!e||0===e.length)continue;const n=Math.min(...e),s=1===e.length?"single":Xe(e)??"single";o.set(n,{uuid:t,circuit:i,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const i=t.circuit.tabs,n=Qe(Math.max(...i));0===Je(e)?r.add(n):l.add(n)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,n=s?et(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&i.states[t]?i.states[t].state:"unknown"}return{monInfo:n,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=it(h.uuid,h.circuit,e,"2 / 4","row-span",i,n,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=nt(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=it(h.uuid,h.circuit,e,"2",h.layout,i,n,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=nt(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=it(p.uuid,p.circuit,e,"3",p.layout,i,n,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ut(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Dt="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Nt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Lt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ht="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",Ft="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function Rt(e,t,i,n,s){return`\n ${n}\n `}class Ot{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,n,s=""){let o;void 0!==n&&(this._configEntryId=n),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const i=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=i?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const n=De(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const n=De(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${i("monitoring.heading")}

\n\n
\n
\n

${i("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${i("monitoring.continuous")}\n \n
\n
\n ${i("monitoring.spike")}\n \n
\n
\n ${i("monitoring.window")}\n \n
\n
\n ${i("monitoring.cooldown")}\n \n
\n\n
\n

${i("notification.heading")}

\n\n
\n ${i("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${i("notification.no_targets")}
`:u.map(e=>{const n=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?i("notification.event_bus_target"):a?`${De(a)} (${De(e)})`:De(e);return``}).join("")}\n
\n
\n
\n\n
\n ${i("notification.priority")}\n \n \n ${"critical"===b?i("notification.hint.critical"):"time-sensitive"===b?i("notification.hint.time_sensitive"):"passive"===b?i("notification.hint.passive"):"active"===b?i("notification.hint.active"):""}\n \n
\n\n
\n ${i("notification.title_template")}\n \n
\n\n
\n ${i("notification.message_template")}\n \n
\n\n
\n ${i("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${i("notification.event_bus_help")} span_panel_current_alert\n ${i("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${i("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${i("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${i("monitoring.col.name")}${i("monitoring.col.continuous")}${i("monitoring.col.spike")}${i("monitoring.col.window")}${i("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const n=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,n),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:i("error.failed_save");o.textContent=`${i("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};n&&n.addEventListener("change",async()=>{const o=n.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,i)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:i("error.failed");a.textContent=`${i("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const n=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!n||!s)return;n.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const i=e.querySelector("#notify-target-select");i&&!i.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const n=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=n.map(e=>"event_bus"===e?i("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):i("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:n.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const n=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,i)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:i})}catch{}},p)};n&&n.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:n.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=i("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const n=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:n});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=i("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:i("error.failed");c.textContent=`${i("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,i,n){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const i of e.querySelectorAll(".mains-toggle"))i.addEventListener("change",async()=>{const n=i.dataset.entity,s=i.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:n,monitoring_enabled:s})})}catch{return void(i.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const i of e.querySelectorAll(".circuit-toggle"))i.addEventListener("change",async()=>{const n=i.dataset.entity,s=i.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:n,monitoring_enabled:s})})}catch{return void(i.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const i=new Map;for(const n of e.querySelectorAll(".threshold-input"))n.addEventListener("input",()=>{const s=`${n.dataset.entity}-${n.dataset.field}`,o=i.get(s);o&&clearTimeout(o),i.set(s,setTimeout(async()=>{const i=parseInt(n.value,10);if(!i||i<1)return;const s=n.dataset.entity,o=n.dataset.field,r=n.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:i})}),await this.render(e,t)}catch{n.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const i of e.querySelectorAll(".reset-btn"))i.addEventListener("click",async()=>{const n=i.dataset.entity;if(!n)return;const s=i.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:n}:{circuit_id:n});await t.callService(a,o,r),await this.render(e,t)})}}function qt(e=""){const t=e?` value="${De(e)}"`:"",n=e?"":"display:none;";return`\n
\n \n \n
\n `}function jt(e,t,n,s,o,a,l){const c=t.entities?.power,d=c?n.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?n.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=De(t.name||i("grid.unknown")),b=Ke(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,i=e?n.states[e]:null,s=i&&parseFloat(i.state)||0;w=`${b.format(s)}A`}else w=`${We(h)}${Ve(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Ut(e,t,i,n,s,o){const a=it(e,t,0,"1","single",i,n,s,o,!0);return`
${a}
`}function Gt(e){return`
${De(e)}
`}function Vt(e,t,i){const n=e.entities?.switch,s=n?t.states[n]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(i.chart_metric||"power")){const i=e.entities?.current,n=i?t.states[i]:null;c=n?Math.abs(parseFloat(n.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Wt(e,t){if(e.always_on)return"always_on";const i=e.entities?.select,n=i?t.states[i]:null;return n?n.state:"unknown"}function Bt(e,t,i){return e.sort((e,n)=>{const s=Vt(e[1],t,i),o=Vt(n[1],t,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value})}function Qt(e){return e.entities?.current??e.entities?.power??""}class Jt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,i,n,s,o){this._unbindEvents(),this._hass=t,this._topology=i,this._config=n,this._monitoringStatus=s;const a=Bt(Object.entries(i.circuits),t,n);let r=o+qt(this._searchQuery);r+='
';for(const[e,i]of a){const o=et(s,Qt(i)),a=Wt(i,t),l=this._expandedUuids.has(e);r+=jt(e,i,t,n,o,a,l),l&&(r+=Ut(e,i,t,n,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,n,s,o,a){this._unbindEvents(),this._hass=t,this._topology=n,this._config=s,this._monitoringStatus=o;const r=i("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(n.circuits)){const i=t.area??r,n=l.get(i);n?n.push([e,t]):l.set(i,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+qt(this._searchQuery);d+='
';for(const e of c){const i=l.get(e);if(!i)continue;const n=Bt(i,t,s);d+=Gt(e);for(const[e,i]of n){const n=et(o,Qt(i)),a=Wt(i,t),r=this._expandedUuids.has(e);d+=jt(e,i,t,s,n,a,r),r&&(d+=Ut(e,i,t,s,n,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,i,n){const s=Ke(n),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=i.circuits[a];if(!r)continue;const{isOn:l,value:c}=Vt(r,t,n),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,i=e?t.states[e]:null,n=i&&parseFloat(i.state)||0;d.innerHTML=`${We(n)}${Ve(n)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const i=t.target;if(!i)return;const n=i.closest(".list-expand-toggle");if(n){const e=n.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(i.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(i.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(i.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=i.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const i=t.target;i&&i.classList.contains("list-search")&&(this._searchQuery=i.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const i=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of i){const i=t.querySelector(".list-circuit-name"),n=(i?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=n?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=n?"":"none")}}const n=e.querySelectorAll(".area-header");for(const e of n){let t=!1,i=e.nextElementSibling;for(;i&&!i.classList.contains("area-header");){if(i.classList.contains("list-row")&&"none"!==i.style.display){t=!0;break}i=i.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),i=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const n=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);n&&n.remove(),i&&i.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const n=this._topology.circuits[e];if(!n)return;const s=et(this._monitoringStatus,Qt(n)),o=Wt(n,this._hass),a=Ut(e,n,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),i&&i.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Xt(e,t){return`${e}|${t}`}class Kt{async build(e,t,i){const n=new Map;for(const e of i)n.set(e.id,e);const s=[];for(const[i,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=n.get(i);t&&s.push((async()=>{try{const n=await je(e,i);return{panelDeviceId:i,panel:t,topology:n.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",i,e),{panelDeviceId:i,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d=new Set;for(const{panelDeviceId:e,panel:i,topology:n}of o){if(!n)continue;const s=i.config_entries?.[0]??null;s&&d.add(s);const o=i.name_by_user??i.name??n.device_name??"",h=t[e],p=h?.circuits??[],u=h?.sub_devices??[];for(const t of p){const i=n.circuits?.[t];if(!i)continue;const l=Xt(e,t),d=a&&o?`${o} · ${i.name}`:i.name;r[l]={...i,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of u){const i=n.sub_devices?.[t];if(!i)continue;const r=Xt(e,t),d=a&&o&&i.name?`${o} · ${i.name}`:i.name??t;l[r]={...i,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(d)}}}const Zt="favorites",Yt="span_panel_favorites_view_state";function ei(e){try{localStorage.setItem(Yt,JSON.stringify(e))}catch{}}let ti=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new It,this._monitoringTab=new Ot,this._listDashCtrl=new Mt,this._listCtrl=new Jt(this._listDashCtrl),this._favCache=new He,this._favCtrl=new Kt,this._favoritesMonitoringTabs=new Map,this._refreshSeq=0,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ne,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ne,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const i=e.querySelector("span-side-panel");i&&(i.hass=this.hass)}}}setConfig(e){}render(){var i,n,s;return i=this.hass?.language,e=i&&t[i]?i:"en",this.hass?this._discovered?oe` + */class Me extends Pe{constructor(e){if(super(e),this.it=re,e.type!==Ae)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===re||null==e)return this._t=void 0,this.it=e;if(e===ae)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Me.directiveName="unsafeHTML",Me.resultType=1;const Te=(e=>(...t)=>({_$litDirective$:e,values:t}))(Me),Ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function De(e){return String(e).replace(/[&<>"']/g,e=>Ie[e]??e)}const Ne="favorites-changed";async function Le(e,t,n={}){const i=await e.callWS({type:"call_service",domain:a,service:t,service_data:n,return_response:!0});return i?.response??null}class He{constructor(){this._map=null,this._lastFetch=0,this._inflight=null}async fetch(e){const t=Date.now();return this._inflight?this._inflight:this._map&&t-this._lastFetch<3e4?this._map:(this._inflight=(async()=>{try{const t=await async function(e){const t=await Le(e,"get_favorites");return t?.favorites??{}}(e);return this._map=t,this._lastFetch=Date.now(),t}catch{return this._map??{}}finally{this._inflight=null}})(),this._inflight)}invalidate(){this._lastFetch=0}clear(){this._map=null,this._lastFetch=0}get map(){return this._map??{}}}function Fe(e){for(const t of Object.values(e)){if((t.circuits?.length??0)>0)return!0;if((t.sub_devices?.length??0)>0)return!0}return!1}const Re=Object.keys(_).filter(e=>"unknown"!==e&&"always_on"!==e);class Oe extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this._hass=null,this._config=null,this._debounceTimers={}}set hass(e){this._hass=e,this.hasAttribute("open")&&this._config&&this._updateLiveState()}get hass(){return this._hass}open(e){this._config=e,this._render(),this.offsetHeight,this.setAttribute("open","")}close(){this.removeAttribute("open"),this._config=null,this.dispatchEvent(new CustomEvent("side-panel-closed",{bubbles:!0,composed:!0}))}_render(){const e=this._config;if(!e)return;const t=this.shadowRoot;if(!t)return;t.innerHTML="";const n=document.createElement("style");n.textContent='\n :host {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 360px;\n max-width: 90vw;\n z-index: 1000;\n transform: translateX(100%);\n transition: transform 0.3s ease;\n pointer-events: none;\n }\n :host([open]) {\n transform: translateX(0);\n pointer-events: auto;\n }\n\n .backdrop {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: -1;\n }\n :host([open]) .backdrop {\n display: block;\n }\n\n .panel {\n height: 100%;\n background: var(--card-background-color, #fff);\n border-left: 1px solid var(--divider-color, #e0e0e0);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--divider-color, #e0e0e0);\n }\n .panel-header .title {\n font-size: 18px;\n font-weight: 500;\n color: var(--primary-text-color, #212121);\n margin: 0;\n }\n .panel-header .subtitle {\n font-size: 13px;\n color: var(--secondary-text-color, #727272);\n margin: 2px 0 0 0;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color, #727272);\n padding: 4px;\n line-height: 1;\n font-size: 20px;\n }\n\n .panel-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .section {\n margin-bottom: 20px;\n }\n .section-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--secondary-text-color, #727272);\n margin: 0 0 8px 0;\n letter-spacing: 0.5px;\n }\n\n .field-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 0;\n }\n .field-label {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n }\n\n select {\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n }\n\n input[type="number"] {\n width: 72px;\n padding: 6px 8px;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 4px;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n font-size: 14px;\n text-align: right;\n }\n input[type="number"]:disabled {\n opacity: 0.5;\n }\n\n .radio-group {\n display: flex;\n gap: 16px;\n padding: 8px 0;\n }\n .radio-group label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n cursor: pointer;\n }\n\n .horizon-bar {\n display: flex;\n border: 1px solid var(--divider-color, #e0e0e0);\n border-radius: 6px;\n overflow: hidden;\n margin-top: 4px;\n }\n .horizon-segment {\n flex: 1;\n padding: 6px 0;\n text-align: center;\n font-size: 13px;\n cursor: pointer;\n background: var(--card-background-color, #fff);\n color: var(--primary-text-color, #212121);\n border: none;\n border-right: 1px solid var(--divider-color, #e0e0e0);\n transition: background 0.15s ease, color 0.15s ease;\n user-select: none;\n line-height: 1.4;\n }\n .horizon-segment:last-child {\n border-right: none;\n }\n .horizon-segment:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .horizon-segment.active {\n background: var(--primary-color, #03a9f4);\n color: #fff;\n font-weight: 600;\n }\n .horizon-segment.referenced {\n box-shadow: inset 0 -3px 0 var(--primary-color, #03a9f4);\n }\n\n .monitoring-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .fav-heart {\n background: none;\n border: 1px solid var(--divider-color, #e0e0e0);\n color: var(--secondary-text-color, #727272);\n border-radius: 4px;\n padding: 2px 6px;\n cursor: pointer;\n font-size: 0.9em;\n margin-right: 6px;\n line-height: 1;\n display: inline-flex;\n align-items: center;\n }\n .fav-heart.active {\n color: var(--primary-color, #03a9f4);\n border-color: var(--primary-color, #03a9f4);\n }\n .fav-heart:hover:not(.active) {\n background: var(--secondary-background-color, #f5f5f5);\n }\n .fav-heart ha-icon {\n --mdc-icon-size: 16px;\n }\n\n .panel-mode-info {\n font-size: 14px;\n color: var(--primary-text-color, #212121);\n line-height: 1.6;\n }\n .panel-mode-info p {\n margin: 0 0 12px 0;\n }\n\n .error-msg {\n color: var(--error-color, #f44336);\n font-size: 0.8em;\n padding: 8px;\n margin: 8px 0;\n background: rgba(244, 67, 54, 0.1);\n border-radius: 4px;\n }\n',t.appendChild(n);const i=document.createElement("div");i.className="backdrop",i.addEventListener("click",()=>this.close()),t.appendChild(i);const s=document.createElement("div");s.className="panel",t.appendChild(s),e.panelMode?this._renderPanelMode(s):e.subDeviceMode?this._renderSubDeviceMode(s,e):this._renderCircuitMode(s,e)}_renderPanelMode(e){const t=this._config,i=this._createHeader(n("sidepanel.graph_settings"),n("sidepanel.global_defaults"));e.appendChild(i);const a=document.createElement("div");a.className="panel-body";const r=document.createElement("div");r.className="error-msg",r.id="error-msg",r.style.display="none",a.appendChild(r);const l=t.graphSettings,c=t.topology,d=l?.global_horizon??s,h=l?.circuits??{},u=document.createElement("div");u.className="section";const g=document.createElement("div");g.className="section-label",g.textContent=n("sidepanel.graph_horizon"),u.appendChild(g);const _=document.createElement("div");_.className="field-row";const f=document.createElement("span");f.className="field-label",f.textContent=n("sidepanel.global_default"),_.appendChild(f);const v=document.createElement("select");for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===d&&(t.selected=!0),v.appendChild(t)}if(v.addEventListener("change",()=>{const e={horizon:v.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_graph_time_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),_.appendChild(v),u.appendChild(_),a.appendChild(u),c?.circuits){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.circuit_scales"),e.appendChild(i);const s=Object.entries(c.circuits).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildFavoriteHeart(a.entities,t.favoriteCircuitUuids?.has(i)??!1);e&&s.appendChild(e)}const l=h[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,u=document.createElement("select");u.dataset.uuid=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),u.appendChild(t)}if(u.addEventListener("change",()=>{this._debounce(`circuit-${i}`,p,()=>{const e={circuit_id:i,horizon:u.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(u),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={circuit_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_graph_horizon",n).then(()=>{u.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}const m=l?.sub_devices??{};if(c?.sub_devices){const e=document.createElement("div");e.className="section";const i=document.createElement("div");i.className="section-label",i.textContent=n("sidepanel.subdevice_scales"),e.appendChild(i);const s=Object.entries(c.sub_devices).sort(([,e],[,t])=>(e.name||"").localeCompare(t.name||""));for(const[i,a]of s){const s=document.createElement("div");s.className="field-row";const r=document.createElement("span");if(r.className="field-label",r.textContent=a.name||i,r.style.cssText="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1;",s.appendChild(r),t.showFavorites&&t.favoritePanelDeviceId){const e=this._buildSubDeviceFavoriteHeart(a.entities,t.favoriteSubDeviceIds?.has(i)??!1);e&&s.appendChild(e)}const l=m[i]||{horizon:d,has_override:!1},c=l.has_override?l.horizon:d,h=document.createElement("select");h.dataset.subdevId=i;for(const e of Object.keys(o)){const t=document.createElement("option");t.value=e;const i=`horizon.${e}`,s=n(i);t.textContent=s!==i?s:e,e===c&&(t.selected=!0),h.appendChild(t)}if(h.addEventListener("change",()=>{this._debounce(`subdev-${i}`,p,()=>{const e={subdevice_id:i,horizon:h.value};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("set_subdevice_graph_horizon",e).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))})}),s.appendChild(h),l.has_override){const e=document.createElement("button");e.textContent="↺",e.title=n("sidepanel.reset_to_global"),Object.assign(e.style,{background:"none",border:"1px solid var(--divider-color, #e0e0e0)",color:"var(--primary-text-color)",borderRadius:"4px",padding:"3px 6px",cursor:"pointer",marginLeft:"4px",fontSize:"0.85em"}),e.addEventListener("click",()=>{const n={subdevice_id:i};t.configEntryId&&(n.config_entry_id=t.configEntryId),this._callDomainService("clear_subdevice_graph_horizon",n).then(()=>{h.value=d,e.remove(),this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${e.message??e}`))}),s.appendChild(e)}e.appendChild(s)}a.appendChild(e)}e.appendChild(a)}_renderCircuitMode(e,t){const n=`${De(String(t.breaker_rating_a))}A · ${De(String(t.voltage))}V · Tabs [${De(String(t.tabs))}]`,i=this._createHeader(De(t.name),n);e.appendChild(i);const s=document.createElement("div");s.className="panel-body",e.appendChild(s);const o=document.createElement("div");o.className="error-msg",o.id="error-msg",o.style.display="none",s.appendChild(o),this._renderRelaySection(s,t),t.showFavorites&&this._renderFavoriteSection(s,t),this._renderSheddingSection(s,t),this._renderGraphHorizonSection(s,t),t.showMonitoring&&this._renderMonitoringSection(s,t)}_favoriteEntityId(e){return e?.current??e?.power??null}_subDeviceFavoriteEntityId(e){if(!e)return null;let t=null;for(const[n,i]of Object.entries(e)){if("sensor"===i.domain)return n;t||(t=n)}return t}_buildSubDeviceFavoriteHeart(e,t){const n=this._subDeviceFavoriteEntityId(e);return n?this._buildHeartButton(n,t):null}_buildFavoriteHeart(e,t){const n=this._favoriteEntityId(e);return n?this._buildHeartButton(n,t):(console.warn("SPAN Panel: circuit has no current/power sensor; favorite heart suppressed"),null)}_buildHeartButton(e,t){const i=document.createElement("button");i.type="button",i.className=t?"fav-heart active":"fav-heart",i.dataset.role="fav-heart",i.title=n("sidepanel.save_to_favorites"),i.setAttribute("role","switch"),i.setAttribute("aria-pressed",String(t)),i.setAttribute("aria-label",n("sidepanel.save_to_favorites"));const s=document.createElement("ha-icon");return s.setAttribute("icon",t?"mdi:heart":"mdi:heart-outline"),i.appendChild(s),i.addEventListener("click",t=>{t.stopPropagation(),this._toggleFavoriteEntity(i,s,e).catch(()=>{})}),i}async _toggleFavoriteEntity(e,t,i){if(!this._hass)return;const s=e.classList.contains("active"),o=!s;e.classList.toggle("active",o),t.setAttribute("icon",o?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(o));try{o?await async function(e,t){const n=await Le(e,"add_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Ne)),n?.favorites??{}}(this._hass,i):await async function(e,t){const n=await Le(e,"remove_favorite",{entity_id:t});return document.dispatchEvent(new CustomEvent(Ne)),n?.favorites??{}}(this._hass,i)}catch(i){e.classList.toggle("active",s),t.setAttribute("icon",s?"mdi:heart":"mdi:heart-outline"),e.setAttribute("aria-pressed",String(s));const o=function(e){if(e instanceof Error)return e.message;if(e&&"object"==typeof e){const t=e;if("string"==typeof t.message&&t.message)return t.message;if("string"==typeof t.error&&t.error)return t.error;if("string"==typeof t.code&&t.code)return t.code}return String(e)}(i);throw this._showError(`${n("sidepanel.favorite_failed")} ${o}`),i}}_renderFavoriteSection(e,t){const n=this._favoriteEntityId(t.entities);n&&this._appendFavoriteHeartSection(e,n,!0===t.isFavorite)}_appendFavoriteHeartSection(e,t,i){const s=document.createElement("div");s.className="section",s.innerHTML=``;const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=n("sidepanel.save_to_favorites"),o.appendChild(a),o.appendChild(this._buildHeartButton(t,i)),s.appendChild(o),e.appendChild(s)}_renderSubDeviceMode(e,t){const n=this._createHeader(De(t.name),De(t.deviceType));e.appendChild(n);const i=document.createElement("div");i.className="panel-body",e.appendChild(i);const s=document.createElement("div");s.className="error-msg",s.id="error-msg",s.style.display="none",i.appendChild(s),t.showFavorites&&this._renderSubDeviceFavoriteSection(i,t),this._renderSubDeviceHorizonSection(i,t)}_renderSubDeviceFavoriteSection(e,t){const n=this._subDeviceFavoriteEntityId(t.entities);n&&this._appendFavoriteHeartSection(e,n,!0===t.isFavorite)}_renderSubDeviceHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={subdevice_id:t.subDeviceId};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_subdevice_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_subdevice_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_createHeader(e,t){const n=document.createElement("div");n.className="panel-header";const i=document.createElement("div"),s=De(e),o=De(t);i.innerHTML=`
${s}
`+(o?`
${o}
`:"");const a=document.createElement("button");return a.className="close-btn",a.innerHTML="✕",a.addEventListener("click",()=>this.close()),n.appendChild(i),n.appendChild(a),n}_renderRelaySection(e,t){if(!1===t.is_user_controllable||!t.entities?.switch)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.breaker");const a=document.createElement("ha-switch");a.dataset.role="relay-toggle";const r=t.entities.switch,l=this._hass?.states?.[r]?.state;"on"===l&&a.setAttribute("checked",""),a.addEventListener("change",()=>{const e=a.hasAttribute("checked")||a.checked;this._callService("switch",e?"turn_on":"turn_off",{entity_id:r}).catch(e=>this._showError(`${n("sidepanel.relay_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderSheddingSection(e,t){if(!t.entities?.select)return;const i=document.createElement("div");i.className="section",i.innerHTML=``;const s=document.createElement("div");s.className="field-row";const o=document.createElement("span");o.className="field-label",o.textContent=n("sidepanel.priority_label");const a=document.createElement("select");a.dataset.role="shedding-select";const r=t.entities.select,l=this._hass?.states?.[r]?.state||"";for(const e of Re){const t=_[e];if(!t)continue;const i=document.createElement("option");i.value=e,i.textContent=n(`shedding.select.${e}`)||t.label(),e===l&&(i.selected=!0),a.appendChild(i)}a.addEventListener("change",()=>{this._callService("select","select_option",{entity_id:r,option:a.value}).catch(e=>this._showError(`${n("sidepanel.shedding_failed")} ${e.message??e}`))}),s.appendChild(o),s.appendChild(a),i.appendChild(s),e.appendChild(i)}_renderGraphHorizonSection(e,t){const i=document.createElement("div");i.className="section";const a=document.createElement("div");a.className="section-label",a.textContent=n("sidepanel.graph_horizon"),i.appendChild(a);const r=t.graphHorizonInfo,l=!0===r?.has_override,c=r?.horizon||s,d=r?.globalHorizon||s,h=document.createElement("div");h.className="horizon-bar";const p=[{key:"global",label:n("sidepanel.global")}];for(const e of Object.keys(o))p.push({key:e,label:e});const u=l?c:"global",g=e=>{for(const t of h.querySelectorAll(".horizon-segment")){const n=t.dataset.horizon;t.classList.toggle("active",n===e),t.classList.toggle("referenced","global"===e&&n===d)}};for(const{key:e,label:i}of p){const s=document.createElement("button");s.type="button",s.className="horizon-segment",s.dataset.horizon=e,s.textContent=i,s.classList.toggle("active",e===u),s.classList.toggle("referenced","global"===u&&e===d),s.addEventListener("click",()=>{if(s.classList.contains("active"))return;const i={circuit_id:t.uuid};t.configEntryId&&(i.config_entry_id=t.configEntryId),"global"===e?(g("global"),this._callDomainService("clear_circuit_graph_horizon",i).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.clear_graph_horizon_failed")} ${e.message??e}`))):(g(e),this._callDomainService("set_circuit_graph_horizon",{...i,horizon:e}).then(()=>{this.dispatchEvent(new CustomEvent("graph-settings-changed",{bubbles:!0,composed:!0}))}).catch(e=>this._showError(`${n("sidepanel.graph_horizon_failed")} ${e.message??e}`)))}),h.appendChild(s)}i.appendChild(h),e.appendChild(i)}_renderMonitoringSection(e,t){const i=document.createElement("div");i.className="section";const s=document.createElement("div");s.className="monitoring-header";const o=document.createElement("div");o.className="section-label",o.textContent=n("sidepanel.monitoring"),o.style.margin="0";const a=document.createElement("ha-switch");a.dataset.role="monitoring-toggle";const r=t.monitoringInfo,l=null!=r&&!1!==r.monitoring_enabled;l&&a.setAttribute("checked",""),s.appendChild(o),s.appendChild(a),i.appendChild(s);const c=document.createElement("div");c.dataset.role="monitoring-details",c.style.display=l?"block":"none",i.appendChild(c);const d=!0===r?.has_override,h=document.createElement("div");h.className="radio-group",h.innerHTML=`\n \n \n `,c.appendChild(h);const p=document.createElement("div");p.dataset.role="threshold-fields",p.style.display=d?"block":"none";const u=r?.continuous_threshold_pct??80,g=r?.spike_threshold_pct??100,_=r?.window_duration_m??15,f=r?.cooldown_duration_m??15;p.appendChild(this._createThresholdRow(n("sidepanel.continuous_pct"),"continuous",u,t)),p.appendChild(this._createThresholdRow(n("sidepanel.spike_pct"),"spike",g,t)),p.appendChild(this._createDurationRow(n("sidepanel.window_duration"),"window-m",_,1,180,"m",t)),p.appendChild(this._createDurationRow(n("sidepanel.cooldown"),"cooldown-m",f,1,180,"m",t)),c.appendChild(p),a.addEventListener("change",()=>{const e=a.checked;c.style.display=e?"block":"none";const i={circuit_id:t.entities?.power||t.uuid,monitoring_enabled:e};t.configEntryId&&(i.config_entry_id=t.configEntryId),this._callDomainService("set_circuit_threshold",i).catch(e=>this._showError(`${n("sidepanel.monitoring_toggle_failed")} ${e.message??e}`))});const v=h.querySelectorAll('input[type="radio"]');for(const e of v)e.addEventListener("change",()=>{const i="custom"===e.value&&e.checked;if(p.style.display=i?"block":"none",!i&&e.checked){const e={circuit_id:t.entities?.power||t.uuid};t.configEntryId&&(e.config_entry_id=t.configEntryId),this._callDomainService("clear_circuit_threshold",e).catch(e=>this._showError(`${n("sidepanel.clear_monitoring_failed")} ${e.message??e}`))}});e.appendChild(i)}_createThresholdRow(e,t,i,s){const o=document.createElement("div");o.className="field-row";const a=document.createElement("span");a.className="field-label",a.textContent=e;const r=document.createElement("input");return r.type="number",r.min="0",r.max="200",r.value=String(i),r.dataset.role=`threshold-${t}`,r.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),o=e.querySelector('[data-role="threshold-window-m"]'),a=e.querySelector('[data-role="threshold-cooldown-m"]'),r={circuit_id:s.entities?.power||s.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:o?Number(o.value):void 0,cooldown_duration_m:a?Number(a.value):void 0};s.configEntryId&&(r.config_entry_id=s.configEntryId),this._callDomainService("set_circuit_threshold",r).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),o.appendChild(a),o.appendChild(r),o}_createDurationRow(e,t,i,s,o,a,r,l=!1){const c=document.createElement("div");c.className="field-row";const d=document.createElement("span");d.className="field-label",d.textContent=e;const h=document.createElement("div"),u=document.createElement("input");u.type="number",u.min=String(s),u.max=String(o),u.value=String(i),u.dataset.role=`threshold-${t}`,l&&(u.disabled=!0);const g=document.createElement("span");return g.textContent=a,h.appendChild(u),h.appendChild(g),l||u.addEventListener("input",()=>{this._debounce(`threshold-${t}`,p,()=>{const e=this.shadowRoot;if(!e)return;const t=e.querySelector('[data-role="threshold-continuous"]'),i=e.querySelector('[data-role="threshold-spike"]'),s=e.querySelector('[data-role="threshold-window-m"]'),o={circuit_id:r.uuid,continuous_threshold_pct:t?Number(t.value):void 0,spike_threshold_pct:i?Number(i.value):void 0,window_duration_m:s?Number(s.value):void 0};r.configEntryId&&(o.config_entry_id=r.configEntryId),this._callDomainService("set_circuit_threshold",o).catch(e=>this._showError(`${n("sidepanel.save_threshold_failed")} ${e.message??e}`))})}),c.appendChild(d),c.appendChild(h),c}_updateLiveState(){if(!this._config||this._config.panelMode)return;const e=this._config;if(!e.subDeviceMode){if(e.entities?.switch){const t=this.shadowRoot?.querySelector('[data-role="relay-toggle"]');if(t){const n=this._hass?.states?.[e.entities.switch]?.state;"on"===n?t.setAttribute("checked",""):t.removeAttribute("checked")}}if(e.entities?.select){const t=this.shadowRoot?.querySelector('[data-role="shedding-select"]');if(t){const n=this._hass?.states?.[e.entities.select]?.state||"";t.value=n}}}}_callService(e,t,n){return this._hass?Promise.resolve(this._hass.callService(e,t,n)):Promise.resolve()}_callDomainService(e,t){return this._hass?this._hass.callWS({type:"call_service",domain:a,service:e,service_data:t}):Promise.resolve()}_showError(e){const t=this.shadowRoot?.getElementById("error-msg");t&&(t.textContent=e,t.style.display="block",setTimeout(()=>{t.style.display="none"},5e3))}_debounce(e,t,n){this._debounceTimers[e]&&clearTimeout(this._debounceTimers[e]),this._debounceTimers[e]=setTimeout(()=>{delete this._debounceTimers[e],n()},t)}}try{customElements.get("span-side-panel")||customElements.define("span-side-panel",Oe)}catch{}async function qe(e,t){const[n,i,s]=await Promise.all([e.callWS({type:"config/area_registry/list"}),e.callWS({type:"config/entity_registry/list"}),e.callWS({type:"config/device_registry/list"})]),o=new Map;for(const e of n)o.set(e.area_id,e.name);const a=new Map;for(const e of i)e.area_id&&a.set(e.entity_id,e.area_id);const r=new Map;for(const e of s)r.set(e.id,e.area_id);let l;if(t.device_id){const e=r.get(t.device_id);e&&(l=o.get(e))}for(const e of Object.values(t.circuits)){let t;for(const n of Object.values(e.entities)){if(!n)continue;const e=a.get(n);if(e){t=o.get(e);break}}t||(t=l),e.area=t}}async function je(e,t){if(!t)throw new Error(n("card.device_not_found"));const i=await e.callWS({type:`${a}/panel_topology`,device_id:t}),s=i.panel_size??function(e){let t=0;for(const n of Object.values(e))if(n)for(const e of n.tabs)e>t&&(t=e);return t>0?t+t%2:0}(i.circuits);if(!s)throw new Error(n("card.topology_error"));const o=await e.callWS({type:"config/device_registry/list"}),r=(l=o.find(e=>e.id===t),l?{id:l.id,name:l.name,name_by_user:l.name_by_user,config_entries:l.config_entries,identifiers:l.identifiers,via_device_id:l.via_device_id,sw_version:l.sw_version,model:l.model}:null);var l;return await qe(e,i),{topology:i,panelDevice:r,panelSize:s}}function Ue(e,t,i={}){const s=De(e.device_name||n("header.default_name")),o=De(e.serial||""),a=De(e.firmware||""),r="current"===(t.chart_metric||"power"),l=!1!==i.showSwitches,c=!!e.panel_entities?.site_power,d=!!e.panel_entities?.dsm_state,h=!!e.panel_entities?.current_power,p=!!e.panel_entities?.feedthrough_power,u=!!e.panel_entities?.pv_power,g=!!e.panel_entities?.battery_level;return`\n
\n
\n
\n

${s}

\n ${o}\n \n ${l?`
\n ${n("header.enable_switches")}\n
\n \n
\n
`:""}\n
\n
\n ${c?`\n
\n ${n("header.site")}\n
\n 0\n ${r?"A":"kW"}\n
\n
`:""}\n ${d?`\n
\n ${n("header.grid")}\n
\n --\n
\n
`:""}\n ${h?`\n
\n ${n("header.upstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${p?`\n
\n ${n("header.downstream")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${u?`\n
\n ${n("header.solar")}\n
\n --\n ${r?"A":"kW"}\n
\n
`:""}\n ${g?`\n
\n ${n("header.battery")}\n
\n \n %\n
\n
`:""}\n
\n
\n
\n
\n ${a}\n
\n \n \n
\n
\n
\n ${Object.entries(_).filter(([e])=>"unknown"!==e).map(([,e])=>{let t;return t=e.icon2?``:e.textLabel?`${e.textLabel}`:``,`
${t}${e.label()}
`}).join("")}\n
\n
\n
\n `}const Ge=u.power;function Ve(e){return Ge.unit(e)}function We(e){return(e<0?"-":"")+Ge.format(e)}function Be(e){return(Math.abs(e)/1e3).toFixed(1)}function Qe(e){return Math.ceil(e/2)}function Je(e){return e%2==0?1:0}function Xe(e){if(2!==e.length)return null;const[t,n]=[Math.min(...e),Math.max(...e)];return Qe(t)===Qe(n)?"row-span":Je(t)===Je(n)?"col-span":"row-span"}function Ke(e){const t=e.chart_metric??i;return u[t]??u[i]}function Ze(e,t){const n=function(e){return Ke(e).entityRole}(t);return e.entities?.[n]??e.entities?.power??null}class Ye{constructor(){this._status=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._status;if(this._status&&n-this._lastFetch<3e4)return this._status;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:i,return_response:!0});this._status=s?.response??null,this._lastFetch=n}catch{this._status=null}finally{this._fetching=!1}return this._status}invalidate(){this._lastFetch=0}get status(){return this._status}clear(){this._status=null,this._lastFetch=0}}function et(e,t){return e?.circuits?e.circuits[t]??null:null}function tt(e){if(!e?.utilization_pct)return"";const t=e.utilization_pct;return t>=100?"utilization-alert":t>=80?"utilization-warning":"utilization-normal"}function nt(e,t,i,s,o,a,c,d,h,p=!1){const u=t.entities?.power,g=u?a.states[u]:null,v=g&&parseFloat(g.state)||0,m=t.device_type===l||v<0,b=t.entities?.switch,y=b?a.states[b]:null,w=y?"on"===y.state:(g?.attributes?.relay_state||t.relay_state)===r,x=t.breaker_rating_a,$=x?`${Math.round(x)}A`:"",S=De(t.name||n("grid.unknown")),C=Ke(c);let E;if("current"===C.entityRole){const e=t.entities?.current,n=e?a.states[e]:null,i=n&&parseFloat(n.state)||0;E=`${C.format(i)}A`}else E=`${We(v)}${Ve(v)}`;const k=h||"unknown";let z="";if("unknown"!==k){const e=_[k]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};z=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}const A=d&&function(e){return!!e&&void 0!==e.continuous_threshold_pct}(d),P=A?f:"#555",M=``;let T="";if(null!=d?.utilization_pct){const e=d.utilization_pct;T=`${Math.round(e)}%`}const I=function(e){return!!e&&null!=e.over_threshold_since}(d);return`\n
\n
\n
\n ${$?`${$}`:""}\n ${S}\n
\n
\n \n ${E}\n \n ${!1!==t.is_user_controllable&&t.entities?.switch?`\n
\n ${n(w?"grid.on":"grid.off")}\n \n
\n `:""}\n
\n
\n
\n ${z}\n ${T}\n ${M}\n
\n
\n
\n `}function it(e,t){return`\n
\n \n
\n `}const st={names:["power","battery power"],suffixes:["_power"]},ot={names:["battery level","battery percentage"],suffixes:["_battery_level","_battery_percentage"]},at={names:["state of energy"],suffixes:["_soe_kwh"]},rt={names:["nameplate capacity"],suffixes:["_nameplate_capacity"]};function lt(e,t){if(!e.entities)return null;for(const[n,i]of Object.entries(e.entities)){if("sensor"!==i.domain)continue;const e=(i.original_name??"").toLowerCase();if(t.names.some(t=>e===t))return n;if(i.unique_id&&t.suffixes.some(e=>i.unique_id.endsWith(e)))return n}return null}function ct(e){return lt(e,st)}function dt(e){return lt(e,ot)}function ht(e){return lt(e,at)}function pt(e){return lt(e,rt)}function ut(e,t,i){const s=!1!==i.show_battery,o=!1!==i.show_evse;if(!e.sub_devices)return"";const a=Object.entries(e.sub_devices).filter(([,e])=>!(e.type===c&&!s)&&!(e.type===d&&!o));if(0===a.length)return"";const r=a.filter(([,e])=>e.type===d).length;let l=0,h="";for(const[e,s]of a){const o=s.type===d?n("subdevice.ev_charger"):s.type===c?n("subdevice.battery"):n("subdevice.fallback"),a=ct(s),p=a?t.states[a]:void 0,u=p&&parseFloat(p.state)||0,g=s.type===c,_=s.type===d,f=g?dt(s):null,v=g?ht(s):null,m=g?pt(s):null,b=gt(s,t,i,new Set([a,f,v,m].filter(e=>null!==e))),y=_t(e,s,g,a,f,v);let w="";g?w="sub-device-bess":_&&(l++,l===r&&r%2==1&&(w="sub-device-full")),h+=`\n
\n
\n ${De(o)}\n ${De(s.name||"")}\n ${a?`${We(u)} ${Ve(u)}`:""}\n \n
\n ${y}\n ${b}\n
\n `}return h}function gt(e,t,n,i){const s=n.visible_sub_entities||{};let o="";if(!e.entities)return o;for(const[n,a]of Object.entries(e.entities)){if(i.has(n))continue;if(!0!==s[n])continue;const r=t.states[n];if(!r)continue;let l=a.original_name||r.attributes.friendly_name||n;const c=e.name||"";let d;if(l.startsWith(c+" ")&&(l=l.slice(c.length+1)),t.formatEntityState)d=t.formatEntityState(r);else{d=r.state;const e=r.attributes.unit_of_measurement||"";e&&(d+=" "+e)}if("Wh"===(r.attributes.unit_of_measurement||"")){const e=parseFloat(r.state);isNaN(e)||(d=(e/1e3).toFixed(1)+" kWh")}o+=`\n
\n ${De(l)}:\n ${De(d)}\n
\n `}return o}function _t(e,t,i,s,o,a){if(i){const t=[{key:`${h}${e}_soc`,title:n("subdevice.soc"),available:!!o},{key:`${h}${e}_soe`,title:n("subdevice.soe"),available:!!a},{key:`${h}${e}_power`,title:n("subdevice.power"),available:!!s}].filter(e=>e.available);return`\n
\n ${t.map(e=>`\n
\n
${De(e.title)}
\n
\n
\n `).join("")}\n
\n `}return s?`
`:""}function ft(e){const t=void 0!==e.history_days||void 0!==e.history_hours||void 0!==e.history_minutes,n=60*(60*(24*(t&&parseInt(String(e.history_days))||0)+(t&&parseInt(String(e.history_hours))||0))+(t?parseInt(String(e.history_minutes))||0:5))*1e3;return Math.max(n,6e4)}function vt(e){const t=o[e];return t?t.ms:o[s].ms}function mt(e){const t=e/1e3;return t<=600?Math.ceil(t):Math.min(5e3,Math.ceil(t/5))}function bt(e){return Math.max(500,Math.floor(e/5e3))}function yt(e,t,n,i,s,o){e.has(t)||e.set(t,[]);const a=e.get(t);a.push({time:i,value:n});const r=a.findIndex(e=>e.time>=s);r>0?a.splice(0,r):-1===r&&(a.length=0),a.length>o&&a.splice(0,a.length-o)}function wt(e,t,n=500){if(0===e.length)return e;e.sort((e,t)=>e.time-t.time);const i=[e[0]];for(let t=1;t=n&&i.push(e[t]);return i.length>t&&i.splice(0,i.length-t),i}async function xt(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=i/36e5>72?"hour":"5minute",r=await e.callWS({type:"recorder/statistics_during_period",start_time:o,statistic_ids:t,period:a,types:["mean"]});for(const[e,t]of Object.entries(r)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=e.mean;if(null==t||!Number.isFinite(t))continue;const n=e.start;n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];t.sort((e,t)=>e.time-t.time),s.set(i,t)}}}async function $t(e,t,n,i,s){const o=new Date(Date.now()-i).toISOString(),a=await e.callWS({type:"history/history_during_period",start_time:o,entity_ids:t,minimal_response:!0,significant_changes_only:!0,no_attributes:!0}),r=mt(i),l=bt(i);for(const[e,t]of Object.entries(a)){const i=n.get(e);if(!i||!t)continue;const o=[];for(const e of t){const t=parseFloat(e.s);if(!Number.isFinite(t))continue;const n=1e3*(e.lu||e.lc||0);n>0&&o.push({time:n,value:t})}if(o.length>0){const e=s.get(i)||[],t=[...o,...e];s.set(i,wt(t,r,l))}}}function St(e){if(!e.sub_devices)return[];const t=[];for(const[n,i]of Object.entries(e.sub_devices)){const e={power:ct(i)};i.type===c&&(e.soc=dt(i),e.soe=ht(i));for(const[i,s]of Object.entries(e))s&&t.push({entityId:s,key:`${h}${n}_${i}`,devId:n})}return t}async function Ct(e,t,n,i,s,o){if(!t||!e)return;const a=new Map;for(const[e,i]of Object.entries(t.circuits)){const t=Ze(i,n);if(!t)continue;let o;o=s&&s.has(e)?vt(s.get(e)):ft(n),a.has(o)||a.set(o,{entityIds:[],uuidByEntity:new Map});const r=a.get(o);r.entityIds.push(t),r.uuidByEntity.set(t,e)}for(const{entityId:e,key:i,devId:s}of St(t)){let t;t=o&&o.has(s)?vt(o.get(s)):ft(n),a.has(t)||a.set(t,{entityIds:[],uuidByEntity:new Map});const r=a.get(t);r.entityIds.push(e),r.uuidByEntity.set(e,i)}const r=[];for(const[t,n]of a){if(0===n.entityIds.length)continue;t>2592e5?r.push(xt(e,n.entityIds,n.uuidByEntity,t,i)):r.push($t(e,n.entityIds,n.uuidByEntity,t,i))}await Promise.all(r)}function Et(e,t,n,s,o,a,r,l,c){const{options:d,series:h}=function(e,t,n,s,o,a=!1){n||(n=u[i]);const r=s?"140, 160, 220":"77, 217, 175",l=`rgb(${r})`,c=Date.now(),d=c-t,h=void 0!==n.fixedMin&&void 0!==n.fixedMax,p=(e??[]).filter(e=>e.time>=d).map(e=>[e.time,Math.abs(e.value)]),g=[{type:"line",data:p,showSymbol:!1,smooth:!1,...a?{}:{step:"end"},lineStyle:{width:1.5,color:l},areaStyle:{color:{type:"linear",x:0,y:0,x2:0,y2:1,colorStops:[{offset:0,color:`rgba(${r}, 0.35)`},{offset:1,color:`rgba(${r}, 0.02)`}]}},itemStyle:{color:l}}],_=p.length>0?function(e){let t=0;for(const n of e)n[1]>t&&(t=n[1]);return t}(p):0,f={type:"value",splitNumber:4,axisLabel:{fontSize:10,formatter:_<10?e=>0===e?"0":e.toFixed(1):e=>n.format(e)},splitLine:{lineStyle:{opacity:.15}}};h?(f.min=n.fixedMin,f.max=n.fixedMax):_<1&&(f.min=0,f.max=1),o&&"current"===n.entityRole&&(f.min=0,f.max=Math.ceil(1.25*o),g.push({type:"line",data:[[d,.8*o],[c,.8*o]],showSymbol:!1,lineStyle:{width:1,color:"rgba(255, 200, 40, 0.6)",type:"dashed"},itemStyle:{color:"transparent"},tooltip:{show:!1}}),g.push({type:"line",data:[[d,o],[c,o]],showSymbol:!1,lineStyle:{width:1.5,color:"rgba(255, 60, 60, 0.7)",type:"solid"},itemStyle:{color:"transparent"},tooltip:{show:!1}}));const v={xAxis:{type:"time",min:d,max:c,axisLabel:{fontSize:10},splitLine:{show:!1}},yAxis:f,grid:{top:8,right:4,bottom:0,left:0,containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"line",lineStyle:{type:"dashed"}},formatter:e=>{if(!e||0===e.length)return"";const t=e[0],i=new Date(t.value[0]).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),s=parseFloat(t.value[1].toFixed(2));return`
${i}
${n.format(s)} ${n.unit(s)}
`}},animation:!1};return{options:v,series:g}}(n,s,o,a,l,c),p=r??120;e.style.minHeight=p+"px";let g=e.querySelector("ha-chart-base");g||(g=document.createElement("ha-chart-base"),g.style.display="block",g.style.width="100%",g.hass=t,e.innerHTML="",e.appendChild(g));const _=e.clientHeight;g.height=(_>0?_:p)+"px",g.hass=t,g.options=d,g.data=h}function kt(e,t,i,s,o,a){if(!e||!i||!t)return;const c=ft(s);let d=0;for(const[,e]of Object.entries(i.circuits)){const n=e.entities?.power;if(!n)continue;const i=t.states[n],s=i&&parseFloat(i.state)||0;e.device_type!==l&&(d+=Math.abs(s))}!function(e,t,n,i,s){const o="current"===(i.chart_metric||"power"),a=e.querySelector(".stat-consumption .stat-value"),r=e.querySelector(".stat-consumption .stat-unit");if(o){const e=n.panel_entities?.site_power,i=e?t.states[e]:null,s=i?parseFloat(i.attributes?.amperage):NaN;a&&(a.textContent=Number.isFinite(s)?Math.abs(s).toFixed(1):"--"),r&&(r.textContent="A")}else{const e=n.panel_entities?.site_power;if(e){const n=t.states[e];n&&(s=Math.abs(parseFloat(n.state)||0))}a&&(a.textContent=Be(s)),r&&(r.textContent="kW")}const l=e.querySelector(".stat-upstream .stat-value"),c=e.querySelector(".stat-upstream .stat-unit");if(l){const e=n.panel_entities?.current_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;l.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",c&&(c.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;l.textContent=Be(e),c&&(c.textContent="kW")}}const d=e.querySelector(".stat-downstream .stat-value"),h=e.querySelector(".stat-downstream .stat-unit");if(d){const e=n.panel_entities?.feedthrough_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;d.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",h&&(h.textContent="A")}else{const e=i?Math.abs(parseFloat(i.state)||0):0;d.textContent=Be(e),h&&(h.textContent="kW")}}const p=e.querySelector(".stat-solar .stat-value"),u=e.querySelector(".stat-solar .stat-unit");if(p){const e=n.panel_entities?.pv_power,i=e?t.states[e]:null;if(o){const e=i?parseFloat(i.attributes?.amperage):NaN;p.textContent=Number.isFinite(e)?Math.abs(e).toFixed(1):"--",u&&(u.textContent="A")}else{if(i){const e=Math.abs(parseFloat(i.state)||0);p.textContent=Be(e)}else p.textContent="--";u&&(u.textContent="kW")}}const g=e.querySelector(".stat-battery .stat-value");if(g){const e=n.panel_entities?.battery_level,i=e?t.states[e]:null;i&&(g.textContent=`${Math.round(parseFloat(i.state)||0)}`)}const _=e.querySelector(".stat-grid-state .stat-value");if(_){const e=n.panel_entities?.dsm_state,i=e?t.states[e]:null;_.textContent=i?t.formatEntityState?.(i)||i.state:"--"}}(e,t,i,s,d);const h=Ke(s),p="current"===h.entityRole;for(const[s,d]of Object.entries(i.circuits)){const i=e.querySelector(`[data-uuid="${s}"]`);if(!i)continue;const u=d.entities?.power,g=u?t.states[u]:null,f=g&&parseFloat(g.state)||0,v=d.device_type===l||f<0,m=d.entities?.switch,b=m?t.states[m]:null,y=b?"on"===b.state:(g?.attributes?.relay_state||d.relay_state)===r,w=i.querySelector(".power-value");if(w)if(p){const e=d.entities?.current,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;w.innerHTML=`${h.format(i)}A`}else w.innerHTML=`${We(f)}${Ve(f)}`;const x=i.querySelector(".toggle-pill");if(x){x.className="toggle-pill "+(y?"toggle-on":"toggle-off");const e=x.querySelector(".toggle-label");e&&(e.textContent=n(y?"grid.on":"grid.off"))}let $;if(i.classList.toggle("circuit-off",!y),i.classList.toggle("circuit-producer",v),d.always_on)$="always_on";else{const e=d.entities?.select,n=e?t.states[e]:null;$=n?n.state:"unknown"}const S=_[$]??_.unknown,C=i.querySelector(".shedding-icon");C&&(C.setAttribute("icon",S.icon),C.style.color=S.color,C.title=S.label());const E=i.querySelector(".shedding-icon-secondary");E&&(S.icon2?(E.setAttribute("icon",S.icon2),E.style.color=S.color,E.style.display=""):E.style.display="none");const k=i.querySelector(".shedding-label");k&&(S.textLabel?(k.textContent=S.textLabel,k.style.color=S.color,k.style.display=""):k.style.display="none");const z=i.querySelector(".chart-container");if(z){const e=o.get(s)||[],n=i.classList.contains("circuit-col-span")?200:100,r=a?.has(s)?vt(a.get(s)):c,p=d.device_type===l;Et(z,t,e,r,h,v,n,d.breaker_rating_a??void 0,p)}}}class zt{constructor(){this._settings=null,this._lastFetch=0,this._fetching=!1}async fetch(e,t){const n=Date.now();if(this._fetching)return this._settings;if(this._settings&&n-this._lastFetch<3e4)return this._settings;this._fetching=!0;try{const i={};t&&(i.config_entry_id=t);const s=await e.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:i,return_response:!0});this._settings=s?.response??null,this._lastFetch=n}catch{this._settings=null}finally{this._fetching=!1}return this._settings}invalidate(){this._lastFetch=0}get settings(){return this._settings}clear(){this._settings=null,this._lastFetch=0}}function At(e,t){if(!e)return s;const n=e.circuits?.[t];return n?.has_override?n.horizon:e.global_horizon??s}function Pt(e,t){if(!e)return s;const n=e.sub_devices?.[t];return n?.has_override?n.horizon:e.global_horizon??s}class Mt{constructor(){this.powerHistory=new Map,this.horizonMap=new Map,this.subDeviceHorizonMap=new Map,this.monitoringCache=new Ye,this.graphSettingsCache=new zt,this._hass=null,this._topology=null,this._config=null,this._configEntryId=null,this._favRefs=null,this._panelFavorites=null,this._showMonitoring=!1,this._updateInterval=null,this._recorderRefreshInterval=null,this._resizeObserver=null,this._lastWidth=0,this._resizeDebounce=null}get hass(){return this._hass}set hass(e){this._hass=e}get topology(){return this._topology}get config(){return this._config}set showMonitoring(e){this._showMonitoring=e}init(e,t,n,i){this._topology=e,this._config=t,this._hass=n,this._configEntryId=i}setFavoriteRefs(e){this._favRefs=e}clearFavoriteRefs(){this._favRefs=null}setPanelFavorites(e){this._panelFavorites=e}get _inFavoritesView(){return null!==this._favRefs}setConfig(e){this._config=e}buildHorizonMaps(e){if(this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),e&&this._topology?.circuits)for(const t of Object.keys(this._topology.circuits))this.horizonMap.set(t,At(e,t));if(e&&this._topology?.sub_devices)for(const t of Object.keys(this._topology.sub_devices))this.subDeviceHorizonMap.set(t,Pt(e,t))}async fetchAndBuildHorizonMaps(){try{this._favRefs?await this._buildFavoritesHorizonMaps():(await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings))}catch{}}async _buildFavoritesHorizonMaps(){if(!this._hass||!this._favRefs||!this._topology)return;const e=new Set;for(const t of Object.values(this._favRefs))t.configEntryId&&e.add(t.configEntryId);const t=new Map;await Promise.all(Array.from(e).map(async e=>{t.set(e,await this._fetchGraphSettingsFresh(e))})),this.horizonMap.clear(),this.subDeviceHorizonMap.clear();for(const e of Object.keys(this._topology.circuits)){const n=this._favRefs[e],i=n?.configEntryId?t.get(n.configEntryId)??null:null,s=n?.targetId??e;this.horizonMap.set(e,At(i,s))}if(this._topology.sub_devices)for(const e of Object.keys(this._topology.sub_devices)){const n=this._favRefs[e],i=n?.configEntryId?t.get(n.configEntryId)??null:null,s=n?.targetId??e;this.subDeviceHorizonMap.set(e,Pt(i,s))}}async loadHistory(){await Ct(this._hass,this._topology,this._config,this.powerHistory,this.horizonMap,this.subDeviceHorizonMap)}recordSamples(){if(!this._topology||!this._hass||!this._config)return;const e=Date.now();for(const[t,n]of Object.entries(this._topology.circuits)){const i=this.horizonMap.get(t)??s;if(!o[i]?.useRealtime)continue;const a=Ze(n,this._config);if(!a)continue;const r=this._hass.states[a];if(!r)continue;const l=parseFloat(r.state);if(isNaN(l))continue;const c=vt(i),d=mt(c),h=bt(c),p=e-c,u=this.powerHistory.get(t)??[];u.length>0&&e-u[u.length-1].time0&&e-u[u.length-1].time0&&this._topology)for(const{key:e,devId:t}of St(this._topology))n.has(t)&&i.add(e);const s=new Map;try{await Ct(this._hass,this._topology,this._config,s,t,n);for(const e of t.keys()){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}for(const e of i){const t=s.get(e);t?this.powerHistory.set(e,t):this.powerHistory.delete(e)}this.updateDOM(e)}catch{}}updateDOM(e){this._hass&&this._topology&&this._config&&(kt(e,this._hass,this._topology,this._config,this.powerHistory,this.horizonMap),function(e,t,n,i,s,o){if(!n.sub_devices)return;const a=ft(i);for(const[i,r]of Object.entries(n.sub_devices)){const n=e.querySelector(`[data-subdev="${i}"]`);if(!n)continue;const l=ct(r);if(l){const e=t.states[l],i=e&&parseFloat(e.state)||0,s=n.querySelector(".sub-power-value");s&&(s.innerHTML=`${We(i)} ${Ve(i)}`)}const c=n.querySelectorAll("[data-chart-key]");for(const e of c){const n=e.dataset.chartKey;if(!n)continue;const r=s.get(n)||[];let l=g.power;n.endsWith("_soc")?l=g.soc:n.endsWith("_soe")&&(l=g.soe);const c=!!e.closest(".bess-chart-col");Et(e,t,r,o?.has(i)?vt(o.get(i)):a,l,!1,c?120:150,void 0,n.endsWith("_soc")||n.endsWith("_soe"))}for(const e of Object.keys(r.entities||{})){const i=n.querySelector(`[data-eid="${e}"]`);if(!i)continue;const s=t.states[e];if(s){let e;if(t.formatEntityState)e=t.formatEntityState(s);else{e=s.state;const t=s.attributes.unit_of_measurement||"";t&&(e+=" "+t)}if("Wh"===(s.attributes.unit_of_measurement||"")){const t=parseFloat(s.state);isNaN(t)||(e=(t/1e3).toFixed(1)+" kWh")}i.textContent=e}}}}(e,this._hass,this._topology,this._config,this.powerHistory,this.subDeviceHorizonMap))}async onGraphSettingsChanged(e){if(this._hass){this._favRefs?await this._buildFavoritesHorizonMaps():(this.graphSettingsCache.invalidate(),await this.graphSettingsCache.fetch(this._hass,this._configEntryId),this.buildHorizonMaps(this.graphSettingsCache.settings)),this.powerHistory.clear();try{await this.loadHistory()}catch{}this.updateDOM(e)}}onToggleClick(e,t){const n=e.target,i=n?.closest(".toggle-pill");if(!i)return;const s=t.querySelector(".slide-confirm");if(!s||!s.classList.contains("confirmed"))return;e.stopPropagation(),e.preventDefault();const o=i.closest("[data-uuid]");if(!o||!this._topology||!this._hass)return;const a=o.dataset.uuid;if(!a)return;const r=this._topology.circuits[a];if(!r)return;const l=r.entities?.switch;if(!l)return;const c=this._hass.states[l];if(!c)return void console.warn("SPAN Panel: switch entity not found:",l);const d="on"===c.state?"turn_off":"turn_on";this._hass.callService("switch",d,{},{entity_id:l}).catch(e=>{console.error("SPAN Panel: switch service call failed:",e)})}async onGearClick(e,t){const n=e.target,i=n?.closest(".gear-icon");if(!i)return;const o=t.querySelector("span-side-panel");if(!o||!this._hass)return;if(o.hass=this._hass,i.classList.contains("panel-gear")){if(this._inFavoritesView)return;return await this.graphSettingsCache.fetch(this._hass,this._configEntryId),void o.open({panelMode:!0,topology:this._topology,graphSettings:this.graphSettingsCache.settings,showFavorites:null!==this._panelFavorites,favoritePanelDeviceId:this._panelFavorites?.panelDeviceId,favoriteCircuitUuids:this._panelFavorites?.circuitUuids,favoriteSubDeviceIds:this._panelFavorites?.subDeviceIds,configEntryId:this._configEntryId})}const a=i.dataset.uuid;if(a&&this._topology){const e=this._topology.circuits[a];if(e){const t=this._favRefs?.[a]??null,n=t&&"circuit"===t.kind?t.targetId:a,i=t?.configEntryId??this._configEntryId;let r,l;t?[r,l]=await Promise.all([this._fetchGraphSettingsFresh(i),this._fetchMonitoringStatusFresh(i)]):(await Promise.all([this.graphSettingsCache.fetch(this._hass,i),this.monitoringCache.fetch(this._hass,i)]),r=this.graphSettingsCache.settings,l=this.monitoringCache.status);const c=e.entities?.current??e.entities?.power,d=c?l?.circuits?.[c]??null:null,h=r?.global_horizon??s,p=r?.circuits?.[n],u=p?{...p,globalHorizon:h}:{horizon:h,has_override:!1,globalHorizon:h},g=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,_=null!==t||(this._panelFavorites?.circuitUuids.has(n)??!1),f=this._inFavoritesView||null!==this._panelFavorites;return void o.open({...e,uuid:n,monitoringInfo:d,showMonitoring:this._showMonitoring,graphHorizonInfo:u,showFavorites:f,favoritePanelDeviceId:g,isFavorite:_,configEntryId:i})}}const r=i.dataset.subdevId;if(r&&this._topology?.sub_devices?.[r]){const e=this._topology.sub_devices[r],t=this._favRefs?.[r]??null,n=t&&"sub_device"===t.kind?t.targetId:r,i=t?.configEntryId??this._configEntryId;let a;t?a=await this._fetchGraphSettingsFresh(i):(await this.graphSettingsCache.fetch(this._hass,i),a=this.graphSettingsCache.settings);const l=a?.global_horizon??s,c=a?.sub_devices?.[n],d=c?{...c,globalHorizon:l}:{horizon:l,has_override:!1,globalHorizon:l},h=t?.panelDeviceId??this._panelFavorites?.panelDeviceId,p=null!==t||(this._panelFavorites?.subDeviceIds.has(n)??!1),u=this._inFavoritesView||null!==this._panelFavorites;o.open({subDeviceMode:!0,subDeviceId:n,name:e.name??n,deviceType:e.type??"",entities:e.entities,graphHorizonInfo:d,showFavorites:u,favoritePanelDeviceId:h,isFavorite:p,configEntryId:i})}}async _fetchGraphSettingsFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_graph_settings",service_data:t,return_response:!0});return n?.response??null}catch{return null}}async _fetchMonitoringStatusFresh(e){if(!this._hass)return null;try{const t={};e&&(t.config_entry_id=e);const n=await this._hass.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:t,return_response:!0}),i=n?.response;return i?{circuits:i.circuits,mains:i.mains}:null}catch{return null}}bindSlideConfirm(e,t){const n=e.querySelector(".slide-confirm-knob"),i=e.querySelector(".slide-confirm-text");if(!n||!i)return;let s=!1,o=0,a=0;const r=t=>{e.classList.contains("confirmed")||(s=!0,o=t-n.offsetLeft,a=e.offsetWidth-n.offsetWidth-4,n.classList.remove("snapping"))},l=e=>{if(!s)return;const t=Math.max(2,Math.min(e-o,a));n.style.left=t+"px"},c=()=>{if(!s)return;s=!1;(n.offsetLeft-2)/a>=.9?(n.style.left=a+"px",e.classList.add("confirmed"),n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock-open"),i.textContent=e.dataset.textOn??"",t&&t.classList.remove("switches-disabled")):(n.classList.add("snapping"),n.style.left="2px")};n.addEventListener("mousedown",e=>{e.preventDefault(),r(e.clientX)}),e.addEventListener("mousemove",e=>l(e.clientX)),e.addEventListener("mouseup",c),e.addEventListener("mouseleave",c),n.addEventListener("touchstart",e=>{e.preventDefault(),r(e.touches[0].clientX)},{passive:!1}),e.addEventListener("touchmove",e=>l(e.touches[0].clientX),{passive:!0}),e.addEventListener("touchend",c),e.addEventListener("touchcancel",c),e.addEventListener("click",()=>{e.classList.contains("confirmed")&&(e.classList.remove("confirmed"),n.classList.add("snapping"),n.style.left="2px",n.querySelector("ha-icon")?.setAttribute("icon","mdi:lock"),i.textContent=e.dataset.textOff??"",t&&t.classList.add("switches-disabled"))})}startIntervals(e,t){this._updateInterval=setInterval(()=>{this.recordSamples(),this.updateDOM(e),t&&t()},1e3),this._recorderRefreshInterval=setInterval(()=>{this.refreshRecorderData(e)},3e4)}stopIntervals(){this._updateInterval&&(clearInterval(this._updateInterval),this._updateInterval=null),this._recorderRefreshInterval&&(clearInterval(this._recorderRefreshInterval),this._recorderRefreshInterval=null),this.cleanupResizeObserver()}setupResizeObserver(e,t){this.cleanupResizeObserver(),t&&(this._lastWidth=t.clientWidth,this._resizeObserver=new ResizeObserver(t=>{const n=t[0];if(!n)return;const i=n.contentRect.width;Math.abs(i-this._lastWidth)<5||(this._lastWidth=i,this._resizeDebounce&&clearTimeout(this._resizeDebounce),this._resizeDebounce=setTimeout(()=>{for(const t of e.querySelectorAll(".chart-container")){const e=t.querySelector("ha-chart-base");e&&e.remove()}this.updateDOM(e)},150))}),this._resizeObserver.observe(t))}cleanupResizeObserver(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._resizeDebounce&&(clearTimeout(this._resizeDebounce),this._resizeDebounce=null)}reset(){this.powerHistory.clear(),this.horizonMap.clear(),this.subDeviceHorizonMap.clear(),this.monitoringCache.clear(),this.graphSettingsCache.clear()}}const Tt="\n :host {\n --span-accent: var(--primary-color, #4dd9af);\n }\n\n ha-card {\n padding: 24px;\n background: var(--card-background-color, #1c1c1c);\n color: var(--primary-text-color, #e0e0e0);\n border-radius: var(--ha-card-border-radius, 12px);\n border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #333));\n box-shadow: var(--ha-card-box-shadow, none);\n }\n\n .panel-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px 16px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n .header-left { flex: 1 1 300px; min-width: 0; }\n .header-center { flex: 0 0 auto; }\n .header-right { flex: 0 1 auto; min-width: 0; }\n\n .panel-identity {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-bottom: 12px;\n }\n\n .panel-title {\n font-size: 1.8em;\n font-weight: 700;\n margin: 0;\n color: var(--primary-text-color, #fff);\n }\n\n .panel-serial {\n font-size: 0.85em;\n color: var(--secondary-text-color, #999);\n font-family: monospace;\n }\n\n .panel-stats {\n display: flex;\n flex-wrap: wrap;\n gap: 16px 32px;\n }\n\n .stat { display: flex; flex-direction: column; }\n .stat-label { font-size: 0.8em; color: var(--secondary-text-color, #999); margin-bottom: 2px; }\n .stat-row { display: flex; align-items: baseline; gap: 2px; }\n .stat-value { font-size: 1.5em; font-weight: 700; color: var(--primary-text-color, #fff); }\n .stat-unit { font-size: 0.7em; font-weight: 400; color: var(--secondary-text-color, #999); }\n\n .header-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; padding-top: 8px; }\n .header-right-top { display: flex; gap: 20px; align-items: center; }\n .meta-item { font-size: 0.8em; color: var(--secondary-text-color, #999); }\n\n .shedding-legend { display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }\n .shedding-legend-item { display: inline-flex; align-items: center; gap: 3px; }\n .shedding-legend-item ha-icon { --mdc-icon-size: 16px; }\n .shedding-legend-secondary { --mdc-icon-size: 12px; opacity: 0.8; }\n .shedding-legend-text { font-size: 9px; font-weight: 600; }\n .shedding-legend-label { font-size: 0.7em; color: var(--secondary-text-color, #999); }\n\n .panel-gear {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--secondary-text-color);\n opacity: 0.6;\n padding: 4px;\n margin-left: 8px;\n vertical-align: middle;\n }\n .panel-gear:hover { opacity: 1; }\n .header-center {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 8px;\n }\n .panel-identity .panel-gear {\n margin-left: 0;\n }\n .slide-confirm {\n position: relative;\n display: inline-flex;\n align-items: center;\n width: 160px;\n height: 28px;\n border-radius: 14px;\n background: color-mix(in srgb, var(--primary-color, #4dd9af) 20%, var(--secondary-background-color, #333));\n vertical-align: middle;\n overflow: hidden;\n user-select: none;\n touch-action: none;\n }\n .slide-confirm-text {\n position: absolute;\n width: 100%;\n text-align: center;\n font-size: 0.65em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n pointer-events: none;\n z-index: 0;\n }\n .slide-confirm-knob {\n position: absolute;\n left: 2px;\n top: 2px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--secondary-text-color, #666);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n z-index: 1;\n transition: none;\n }\n .slide-confirm-knob ha-icon {\n --mdc-icon-size: 14px;\n color: var(--card-background-color, #1c1c1c);\n }\n .slide-confirm-knob.snapping {\n transition: left 0.25s ease;\n }\n .slide-confirm.confirmed {\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n }\n .slide-confirm.confirmed .slide-confirm-text {\n color: var(--state-active-color, var(--span-accent));\n }\n .slide-confirm.confirmed .slide-confirm-knob {\n background: var(--state-active-color, var(--span-accent));\n }\n .switches-disabled .toggle-pill {\n opacity: 0.3;\n pointer-events: none;\n }\n .unit-toggle {\n display: inline-flex;\n background: var(--secondary-background-color, #333);\n border-radius: 6px;\n overflow: hidden;\n margin-left: 8px;\n }\n .unit-btn {\n padding: 4px 10px;\n border: none;\n background: none;\n color: var(--secondary-text-color);\n font-size: 0.75em;\n font-weight: 600;\n cursor: pointer;\n }\n .unit-btn.unit-active {\n background: var(--primary-color, #4dd9af);\n color: var(--text-primary-color, #000);\n }\n\n .monitoring-summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 16px;\n font-size: 0.8em;\n background: rgba(76, 175, 80, 0.1);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n }\n .monitoring-active { color: #4caf50; }\n .monitoring-counts { display: flex; gap: 12px; }\n .count-warning { color: #ff9800; }\n .count-alert { color: #f44336; }\n .count-overrides { color: var(--secondary-text-color); }\n\n .panel-grid {\n display: grid;\n grid-template-columns: 28px 1fr 1fr 28px;\n gap: 8px;\n align-items: stretch;\n }\n\n .tab-label {\n display: flex;\n align-items: center;\n font-size: 0.85em;\n font-weight: 600;\n color: var(--secondary-text-color, #999);\n user-select: none;\n }\n .tab-left { justify-content: flex-start; }\n .tab-right { justify-content: flex-end; }\n\n .circuit-slot {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px 20px;\n min-height: 140px;\n transition: opacity 0.3s;\n position: relative;\n overflow: hidden;\n }\n\n .circuit-col-span { min-height: 280px; }\n .circuit-row-span { border-left: 3px solid var(--span-accent); }\n .circuit-off .circuit-name,\n .circuit-off .breaker-badge,\n .circuit-off .power-value,\n .circuit-off .chart-container { opacity: 0.35; }\n .circuit-off .toggle-pill,\n .circuit-off .gear-icon { opacity: 1; }\n\n .circuit-empty {\n opacity: 0.2;\n min-height: 60px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-style: dashed;\n }\n .empty-label { color: var(--secondary-text-color, #999); font-size: 0.85em; }\n\n .circuit-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 6px;\n gap: 8px;\n }\n\n .circuit-info { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }\n\n .breaker-badge {\n background: color-mix(in srgb, var(--span-accent) 15%, transparent);\n color: var(--span-accent);\n font-size: 0.7em;\n font-weight: 700;\n padding: 2px 7px;\n border-radius: 4px;\n white-space: nowrap;\n border: 1px solid color-mix(in srgb, var(--span-accent) 25%, transparent);\n flex-shrink: 0;\n }\n\n .circuit-name {\n font-size: 0.9em;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--primary-text-color, #e0e0e0);\n }\n\n .circuit-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }\n\n .power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .power-value strong { font-weight: 700; font-size: 1.1em; }\n .power-unit { font-size: 0.8em; font-weight: 400; color: var(--secondary-text-color, #999); margin-left: 1px; }\n .circuit-producer .power-value strong { color: var(--info-color, #4fc3f7); }\n\n .toggle-pill {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 2px 4px;\n border-radius: 10px;\n cursor: pointer;\n font-size: 0.65em;\n font-weight: 600;\n transition: background 0.2s;\n user-select: none;\n min-width: 40px;\n }\n .toggle-on {\n padding-left: 6px;\n background: color-mix(in srgb, var(--state-active-color, var(--span-accent)) 25%, transparent);\n color: var(--state-active-color, var(--span-accent));\n }\n .toggle-off {\n padding-right: 6px;\n background: color-mix(in srgb, var(--secondary-text-color) 15%, transparent);\n color: var(--secondary-text-color, #999);\n }\n .toggle-knob {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n transition: background 0.2s, margin 0.2s;\n }\n .toggle-on .toggle-knob {\n background: var(--state-active-color, var(--span-accent));\n margin-left: auto;\n }\n .toggle-off .toggle-knob {\n background: var(--secondary-text-color, #999);\n margin-right: auto;\n order: -1;\n }\n\n .circuit-status {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-top: 4px;\n padding: 0 4px;\n }\n .shedding-icon { opacity: 0.8; cursor: default; }\n .shedding-composite {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n }\n .shedding-icon-secondary { opacity: 0.8; }\n .shedding-label {\n font-size: 10px;\n font-weight: 600;\n opacity: 0.8;\n }\n .gear-icon {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n opacity: 0.6;\n transition: opacity 0.2s;\n margin-left: auto;\n }\n .gear-icon:hover { opacity: 1; }\n .utilization {\n font-size: 0.75em;\n font-weight: 600;\n }\n .utilization-normal { color: #4caf50; }\n .utilization-warning { color: #ff9800; }\n .utilization-alert { color: #f44336; }\n .circuit-alert {\n border-color: #f44336 !important;\n box-shadow: 0 0 8px rgba(244, 67, 54, 0.3);\n }\n .circuit-custom-monitoring {\n border-left: 3px solid #ff9800;\n }\n\n .chart-container {\n width: 100%;\n aspect-ratio: 4 / 1;\n margin-top: 4px;\n overflow: hidden;\n min-width: 0;\n }\n\n .sub-devices {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .sub-device {\n background: var(--secondary-background-color, var(--card-background-color, #2a2a2a));\n border: 1px solid var(--divider-color, #333);\n border-radius: 12px;\n padding: 14px 16px;\n }\n .sub-device-bess,\n .sub-device-full {\n grid-column: 1 / -1;\n }\n\n .sub-device-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 8px; }\n .sub-device-type { font-size: 0.7em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--span-accent); }\n .sub-device-name { font-size: 0.85em; color: var(--secondary-text-color, #999); flex: 1; }\n .sub-power-value { font-size: 0.9em; color: var(--primary-text-color, #fff); white-space: nowrap; }\n .sub-power-value strong { font-weight: 700; font-size: 1.1em; }\n .sub-device .chart-container { margin-bottom: 8px; aspect-ratio: auto; }\n\n .bess-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(0, 1fr));\n gap: 12px;\n margin-bottom: 10px;\n }\n .bess-chart-col { min-width: 0; }\n .bess-chart-title {\n font-size: 0.75em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--secondary-text-color, #999);\n margin-bottom: 4px;\n }\n .bess-chart-col .chart-container { aspect-ratio: auto; }\n .sub-entity { display: flex; gap: 6px; padding: 3px 0; font-size: 0.85em; }\n .sub-entity-name { color: var(--secondary-text-color, #999); }\n .sub-entity-value { font-weight: 500; color: var(--primary-text-color, #e0e0e0); }\n\n /* ── Shared tab bar ────────────────────────────────────── */\n\n .shared-tab-bar {\n display: flex;\n gap: 0;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--divider-color, #333);\n }\n\n .shared-tab {\n padding: 8px 16px;\n cursor: pointer;\n font-size: 0.9em;\n font-weight: 500;\n color: var(--primary-text-color);\n opacity: 0.6;\n border: none;\n border-bottom: 2px solid transparent;\n background: none;\n transition: opacity 0.15s;\n }\n\n .shared-tab:hover {\n opacity: 0.85;\n }\n\n .shared-tab.active {\n opacity: 1;\n border-bottom-color: var(--span-accent);\n }\n\n /* ── List view search ──────────────────────────────────── */\n\n .list-search-container {\n margin-bottom: 12px;\n position: relative;\n }\n\n .list-search {\n width: 100%;\n padding: 8px 36px 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--divider-color, #333);\n background: var(--secondary-background-color, #2a2a2a);\n color: var(--primary-text-color);\n font-size: 0.9em;\n box-sizing: border-box;\n outline: none;\n }\n\n .list-search:focus {\n border-color: var(--span-accent);\n }\n\n .list-search-clear {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 2px;\n display: flex;\n align-items: center;\n opacity: 0.7;\n }\n\n .list-search-clear:hover {\n opacity: 1;\n }\n\n .list-unit-toggle {\n display: inline-flex;\n margin-bottom: 12px;\n }\n\n /* ── List rows ─────────────────────────────────────────── */\n\n .list-view {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n\n .list-row {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n gap: 10px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.15s;\n }\n\n .list-row:hover {\n background: var(--secondary-background-color, #2a2a2a);\n }\n\n .list-row.circuit-off {\n opacity: 0.5;\n }\n\n .list-row.list-row-expanded {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n border-bottom-color: transparent;\n }\n\n .list-circuit-name {\n flex: 1;\n color: var(--primary-text-color);\n font-size: 0.9em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .list-status-badge {\n font-size: 0.75em;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 4px;\n flex-shrink: 0;\n }\n\n .list-status-on {\n color: #4dd9af;\n }\n\n .list-status-off {\n color: #f44336;\n }\n\n .list-power-value {\n font-size: 0.9em;\n font-weight: 600;\n min-width: 70px;\n text-align: right;\n flex-shrink: 0;\n }\n\n .list-expand-toggle {\n background: none;\n border: none;\n color: var(--secondary-text-color);\n cursor: pointer;\n padding: 4px;\n transition: transform 0.2s;\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .list-expand-toggle.expanded {\n transform: rotate(180deg);\n }\n\n /* ── Expanded circuit content ──────────────────────────── */\n\n .list-expanded-content {\n padding: 12px;\n background: var(--card-background-color, #1c1c1c);\n border: 1px solid var(--divider-color, #333);\n border-top: none;\n border-radius: 0 0 8px 8px;\n margin-top: -6px;\n margin-bottom: 2px;\n }\n\n .list-expanded-content .circuit-slot {\n border: none;\n margin: 0;\n background: none;\n }\n\n /* ── Area headers ──────────────────────────────────────── */\n\n .area-header {\n padding: 16px 12px 6px;\n font-weight: 600;\n font-size: 0.85em;\n color: var(--secondary-text-color);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n /* ── No results ────────────────────────────────────────── */\n\n .list-no-results {\n padding: 24px;\n text-align: center;\n color: var(--secondary-text-color);\n }\n\n";class It{constructor(){this._ctrl=new Mt,this._container=null,this._onGearClick=null,this._onToggleClick=null,this._onSidePanelClosed=null,this._onGraphSettingsChanged=null}get hass(){return this._ctrl.hass}set hass(e){this._ctrl.hass=e}setPanelFavorites(e){this._ctrl.setPanelFavorites(e)}async render(e,t,i,s,o){let a,r;this.stop(),this._ctrl.reset(),this._ctrl.showMonitoring=!0,this._container=e,this._ctrl.hass=t;try{const e=await je(t,i);a=e.topology,r=e.panelSize}catch(t){return void(e.innerHTML=`

${De(t.message)}

`)}this._ctrl.init(a,s,t,o??null),await this._ctrl.monitoringCache.fetch(t,o??null),await this._ctrl.fetchAndBuildHorizonMaps();const l=Math.ceil(r/2),c=this._ctrl.monitoringCache.status,d=Ue(a,s),h=function(e){if(!e)return"";const t=Object.values(e.circuits??{}),i=Object.values(e.mains??{}),s=[...t,...i],o=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=80&&e.utilization_pct<100).length,a=s.filter(e=>void 0!==e.utilization_pct&&e.utilization_pct>=100).length,r=s.filter(e=>e.has_override).length;return`\n
\n ✓ ${n("status.monitoring")} · ${t.length} ${n("status.circuits")} · ${i.length} ${n("status.mains")}\n \n ${o>0?`${o} ${n(o>1?"status.warnings":"status.warning")}`:""}\n ${a>0?`${a} ${n(a>1?"status.alerts":"status.alert")}`:""}\n ${r>0?`${r} ${n(r>1?"status.overrides":"status.override")}`:""}\n \n
\n `}(c),p=function(e,t,n,i,s){const o=new Map,a=new Set;for(const[t,n]of Object.entries(e.circuits)){const e=n.tabs;if(!e||0===e.length)continue;const i=Math.min(...e),s=1===e.length?"single":Xe(e)??"single";o.set(i,{uuid:t,circuit:n,layout:s});for(const t of e)a.add(t)}const r=new Set,l=new Set;for(const[e,t]of o)if("col-span"===t.layout){const n=t.circuit.tabs,i=Qe(Math.max(...n));0===Je(e)?r.add(i):l.add(i)}function c(e){const t=e.circuit.entities?.current??e.circuit.entities?.power,i=s?et(s,t??""):null;let o;if(e.circuit.always_on)o="always_on";else{const t=e.circuit.entities?.select;o=t&&n.states[t]?n.states[t].state:"unknown"}return{monInfo:i,sheddingPriority:o}}let d="";for(let e=1;e<=t;e++){const t=2*e-1,s=2*e,h=o.get(t),p=o.get(s);if(d+=`
${t}
`,h&&"row-span"===h.layout){const{monInfo:t,sheddingPriority:o}=c(h);d+=nt(h.uuid,h.circuit,e,"2 / 4","row-span",n,i,t,o),d+=`
${s}
`;continue}if(!r.has(e))if(!h||"col-span"!==h.layout&&"single"!==h.layout)a.has(t)||(d+=it(e,"2"));else{const{monInfo:t,sheddingPriority:s}=c(h);d+=nt(h.uuid,h.circuit,e,"2",h.layout,n,i,t,s)}if(!l.has(e))if(!p||"col-span"!==p.layout&&"single"!==p.layout)a.has(s)||(d+=it(e,"3"));else{const{monInfo:t,sheddingPriority:s}=c(p);d+=nt(p.uuid,p.circuit,e,"3",p.layout,n,i,t,s)}d+=`
${s}
`}return d}(a,l,t,s,c),u=ut(a,t,s);e.innerHTML=`\n \n ${d}\n ${h}\n ${u?`
${u}
`:""}\n ${!1!==s.show_panel?`\n
\n ${p}\n
\n `:""}\n \n `,this._onGearClick=t=>{this._ctrl.onGearClick(t,e)},this._onToggleClick=t=>{this._ctrl.onToggleClick(t,e)},e.addEventListener("click",this._onGearClick),e.addEventListener("click",this._onToggleClick),this._onSidePanelClosed=()=>{this._ctrl.monitoringCache.invalidate(),this._ctrl.graphSettingsCache.invalidate()},e.addEventListener("side-panel-closed",this._onSidePanelClosed),this._onGraphSettingsChanged=()=>this._ctrl.onGraphSettingsChanged(e),e.addEventListener("graph-settings-changed",this._onGraphSettingsChanged);try{await this._ctrl.loadHistory()}catch{}this._ctrl.updateDOM(e);const g=e.querySelector(".slide-confirm");g&&(this._ctrl.bindSlideConfirm(g,e),e.classList.add("switches-disabled")),this._ctrl.setupResizeObserver(e,e),this._ctrl.startIntervals(e)}stop(){this._ctrl.stopIntervals(),this._container&&(this._onGearClick&&(this._container.removeEventListener("click",this._onGearClick),this._onGearClick=null),this._onToggleClick&&(this._container.removeEventListener("click",this._onToggleClick),this._onToggleClick=null),this._onSidePanelClosed&&(this._container.removeEventListener("side-panel-closed",this._onSidePanelClosed),this._onSidePanelClosed=null),this._onGraphSettingsChanged&&(this._container.removeEventListener("graph-settings-changed",this._onGraphSettingsChanged),this._onGraphSettingsChanged=null))}}const Dt="\n display:flex;align-items:center;gap:8px;margin-bottom:8px;\n",Nt="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;width:80px;font-size:0.85em;\n",Lt="\n min-width:130px;font-size:0.85em;color:var(--secondary-text-color);\n",Ht="\n min-width:160px;font-size:0.85em;color:var(--secondary-text-color);\n",Ft="\n background:var(--secondary-background-color,#333);\n border:1px solid var(--divider-color);\n color:var(--primary-text-color);\n border-radius:4px;padding:6px 10px;flex:1;font-size:0.85em;\n font-family:monospace;\n";function Rt(e,t,n,i,s){return`\n ${i}\n `}class Ot{constructor(){this._debounceTimer=null,this._configEntryId=null,this._notifyCloseHandler=null,this._headerHTML=""}stop(){this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null),this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null)}async render(e,t,i,s=""){let o;void 0!==i&&(this._configEntryId=i),this._headerHTML=s,this._notifyCloseHandler&&(document.removeEventListener("click",this._notifyCloseHandler),this._notifyCloseHandler=null);try{const e={};this._configEntryId&&(e.config_entry_id=this._configEntryId);const n=await t.callWS({type:"call_service",domain:a,service:"get_monitoring_status",service_data:e,return_response:!0});o=n?.response||null}catch{o=null}const r=o?.global_settings??{},l=!0===o?.enabled,c=o?.circuits??{},d=o?.mains??{},h=new Set;for(const e of Object.keys(t.states||{}))e.startsWith("notify.")&&h.add(e);const p=new Set(["notify","send_message"]);for(const e of Object.keys(t.services?.notify||{}))p.has(e)||h.add(`notify.${e}`);h.add("event_bus");const u=[...h].sort(),g=r.notify_targets??"",_=("string"==typeof g?g.split(","):g).map(e=>e.trim()).filter(Boolean),f=u.length>0&&u.every(e=>_.includes(e)),v=r.notification_title_template??"SPAN: {name} {alert_type}",m=r.notification_message_template??"{name} at {current_a}A ({utilization_pct}% of {breaker_rating_a}A rating)",b=r.notification_priority??"default",y=Object.entries(c).sort(([,e],[,t])=>(e.name??"").localeCompare(t.name??"")),w=Object.entries(d),x=[...y,...w],$=x.length>0&&x.every(([,e])=>!1!==e.monitoring_enabled),S=x.some(([,e])=>!1!==e.monitoring_enabled),C=y.map(([e,t])=>{const i=De(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","circuit")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","circuit")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","circuit")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","circuit")}\n \n ${o?``:""}\n \n \n `}).join(""),E=Object.entries(d).map(([e,t])=>{const i=De(t.name??e),s=!1!==t.monitoring_enabled,o=!0===t.has_override,a=s?"":"opacity:0.4;",r=De(e);return`\n \n \n \n \n ${Rt(r,"continuous_threshold_pct",t.continuous_threshold_pct,"%","mains")}\n ${Rt(r,"spike_threshold_pct",t.spike_threshold_pct,"%","mains")}\n ${Rt(r,"window_duration_m",t.window_duration_m,"m","mains")}\n ${Rt(r,"cooldown_duration_m",t.cooldown_duration_m,"m","mains")}\n \n ${o?``:""}\n \n \n `}).join("");e.innerHTML=`\n ${this._headerHTML}\n
\n

${n("monitoring.heading")}

\n\n
\n
\n

${n("monitoring.global_settings")}

\n \n
\n\n
\n
\n ${n("monitoring.continuous")}\n \n
\n
\n ${n("monitoring.spike")}\n \n
\n
\n ${n("monitoring.window")}\n \n
\n
\n ${n("monitoring.cooldown")}\n \n
\n\n
\n

${n("notification.heading")}

\n\n
\n ${n("notification.targets")}\n \n
\n \n
\n ${0===u.length?`
${n("notification.no_targets")}
`:u.map(e=>{const i=_.includes(e),s="event_bus"===e,o=s?null:t.states[e],a=o?.attributes?.friendly_name,r=s?n("notification.event_bus_target"):a?`${De(a)} (${De(e)})`:De(e);return``}).join("")}\n
\n
\n
\n\n
\n ${n("notification.priority")}\n \n \n ${"critical"===b?n("notification.hint.critical"):"time-sensitive"===b?n("notification.hint.time_sensitive"):"passive"===b?n("notification.hint.passive"):"active"===b?n("notification.hint.active"):""}\n \n
\n\n
\n ${n("notification.title_template")}\n \n
\n\n
\n ${n("notification.message_template")}\n \n
\n\n
\n ${n("notification.placeholders")} {name} {entity_id} {alert_type}\n {current_a} {breaker_rating_a} {threshold_pct}\n {utilization_pct} {window_m} {local_time}\n
\n
\n ${n("notification.event_bus_help")} span_panel_current_alert\n ${n("notification.event_bus_payload")} alert_source alert_id\n alert_name alert_type current_a\n breaker_rating_a threshold_pct utilization_pct\n panel_serial window_duration_s local_time\n
\n\n
\n ${n("notification.test_label")}\n \n \n
\n
\n\n
\n
\n\n

${n("monitoring.monitored_points")}

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ${E}\n ${C}\n \n
${n("monitoring.col.name")}${n("monitoring.col.continuous")}${n("monitoring.col.spike")}${n("monitoring.col.window")}${n("monitoring.col.cooldown")}
\n \n
\n
\n `;const k=e.querySelector("#toggle-all-circuits");k&&!$&&S&&(k.indeterminate=!0);const z=e.querySelector("#notify-all-targets");if(z&&u.length>0){const e=_.length>0;!f&&e&&(z.indeterminate=!0)}this._bindGlobalControls(e,t),this._bindNotifyTargetSelect(e,t),this._bindNotificationSettings(e,t),this._bindToggleAll(e,t,c,d),this._bindCircuitToggles(e,t),this._bindMainsToggles(e,t),this._bindThresholdInputs(e,t),this._bindResetButtons(e,t)}_serviceData(e){return this._configEntryId&&(e.config_entry_id=this._configEntryId),e}_callSetGlobal(e,t){return e.callWS({type:"call_service",domain:a,service:"set_global_monitoring",service_data:this._serviceData({...t})})}_bindGlobalControls(e,t){const i=e.querySelector("#monitoring-enabled"),s=e.querySelector("#global-fields"),o=e.querySelector("#global-status"),a=()=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{const i={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};try{await this._callSetGlobal(t,i),await this.render(e,t)}catch(e){if(o){const t=e instanceof Error?e.message:n("error.failed_save");o.textContent=`${n("error.prefix")} ${t}`,o.style.color="var(--error-color, #f44336)"}}},p)};i&&i.addEventListener("change",async()=>{const o=i.checked;s&&(s.style.opacity=o?"":"0.4",s.style.pointerEvents=o?"":"none");const a=e.querySelector("#global-status");try{if(o){const n={continuous_threshold_pct:parseInt(e.querySelector("#g-continuous").value,10),spike_threshold_pct:parseInt(e.querySelector("#g-spike").value,10),window_duration_m:parseInt(e.querySelector("#g-window").value,10),cooldown_duration_m:parseInt(e.querySelector("#g-cooldown").value,10)};await this._callSetGlobal(t,n)}else await this._callSetGlobal(t,{enabled:!1})}catch(e){if(a){const t=e instanceof Error?e.message:n("error.failed");a.textContent=`${n("error.prefix")} ${t}`,a.style.color="var(--error-color, #f44336)"}return}await this.render(e,t)});for(const t of e.querySelectorAll("#global-fields input[type=number]"))t.addEventListener("input",a)}_bindNotifyTargetSelect(e,t){const i=e.querySelector("#notify-target-btn"),s=e.querySelector("#notify-target-dropdown"),o=e.querySelector("#notify-target-label");if(!i||!s)return;i.addEventListener("click",e=>{e.stopPropagation();const t="none"!==s.style.display;s.style.display=t?"none":"block"});const a=t=>{const n=e.querySelector("#notify-target-select");n&&!n.contains(t.target)&&(s.style.display="none")};document.addEventListener("click",a),this._notifyCloseHandler=a;const r=()=>{const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value);if(o){const e=i.map(e=>"event_bus"===e?n("notification.event_bus_target"):e);o.textContent=e.length?e.join(", "):n("notification.none_selected")}const s=e.querySelector("#notify-all-targets");if(s){const t=[...e.querySelectorAll(".notify-target-cb")];s.checked=t.length>0&&t.every(e=>e.checked),s.indeterminate=!s.checked&&t.some(e=>e.checked)}this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{notify_targets:i.join(", ")})}catch{}},p)},l=e.querySelector("#notify-all-targets");l&&l.addEventListener("change",()=>{for(const t of e.querySelectorAll(".notify-target-cb"))t.checked=l.checked;const t=e.querySelector("#notify-target-btn");t&&(t.style.opacity=l.checked?"0.4":"",t.style.pointerEvents=l.checked?"none":""),l.checked&&(s.style.display="none"),r()});for(const t of e.querySelectorAll(".notify-target-cb"))t.addEventListener("change",()=>{r()})}_bindNotificationSettings(e,t){const i=e.querySelector("#g-priority"),s=e.querySelector("#g-title-template"),o=e.querySelector("#g-message-template"),r=(e,n)=>{this._debounceTimer&&clearTimeout(this._debounceTimer),this._debounceTimer=setTimeout(async()=>{try{await this._callSetGlobal(t,{[e]:n})}catch{}},p)};i&&i.addEventListener("change",async()=>{try{await this._callSetGlobal(t,{notification_priority:i.value}),await this.render(e,t)}catch{}}),s&&s.addEventListener("input",()=>{r("notification_title_template",s.value)}),o&&o.addEventListener("input",()=>{r("notification_message_template",o.value)});const l=e.querySelector("#test-notification-btn"),c=e.querySelector("#test-notification-status");l&&l.addEventListener("click",async()=>{l.disabled=!0,c&&(c.textContent=n("notification.test_sending"),c.style.color="var(--secondary-text-color)");try{this._debounceTimer&&(clearTimeout(this._debounceTimer),this._debounceTimer=null);const i=[...e.querySelectorAll(".notify-target-cb:checked")].map(e=>e.value).join(", ");await this._callSetGlobal(t,{notify_targets:i});const s={};this._configEntryId&&(s.config_entry_id=this._configEntryId),await t.callWS({type:"call_service",domain:a,service:"test_notification",service_data:s}),c&&(c.textContent=n("notification.test_sent"),c.style.color="var(--success-color, #4caf50)")}catch(e){if(c){const t=e instanceof Error?e.message:n("error.failed");c.textContent=`${n("error.prefix")} ${t}`,c.style.color="var(--error-color, #f44336)"}}finally{l.disabled=!1}})}_bindToggleAll(e,t,n,i){const s=e.querySelector("#toggle-all-circuits");s&&s.addEventListener("change",async()=>{const o=s.checked,r=[...Object.keys(n).map(e=>t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:e,monitoring_enabled:o})}).catch(()=>{})),...Object.keys(i).map(e=>t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:e,monitoring_enabled:o})}).catch(()=>{}))];await Promise.all(r),await this.render(e,t)})}_bindMainsToggles(e,t){for(const n of e.querySelectorAll(".mains-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_mains_threshold",service_data:this._serviceData({leg:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindCircuitToggles(e,t){for(const n of e.querySelectorAll(".circuit-toggle"))n.addEventListener("change",async()=>{const i=n.dataset.entity,s=n.checked;try{await t.callWS({type:"call_service",domain:a,service:"set_circuit_threshold",service_data:this._serviceData({circuit_id:i,monitoring_enabled:s})})}catch{return void(n.checked=!s)}await this.render(e,t)})}_bindThresholdInputs(e,t){const n=new Map;for(const i of e.querySelectorAll(".threshold-input"))i.addEventListener("input",()=>{const s=`${i.dataset.entity}-${i.dataset.field}`,o=n.get(s);o&&clearTimeout(o),n.set(s,setTimeout(async()=>{const n=parseInt(i.value,10);if(!n||n<1)return;const s=i.dataset.entity,o=i.dataset.field,r=i.dataset.type,l="mains"===r?"set_mains_threshold":"set_circuit_threshold",c="mains"===r?"leg":"circuit_id";try{await t.callWS({type:"call_service",domain:a,service:l,service_data:this._serviceData({[c]:s,[o]:n})}),await this.render(e,t)}catch{i.style.borderColor="var(--error-color, #f44336)"}},800))})}_bindResetButtons(e,t){for(const n of e.querySelectorAll(".reset-btn"))n.addEventListener("click",async()=>{const i=n.dataset.entity;if(!i)return;const s=n.dataset.type,o="mains"===s?"clear_mains_threshold":"clear_circuit_threshold",r=this._serviceData("mains"===s?{leg:i}:{circuit_id:i});await t.callService(a,o,r),await this.render(e,t)})}}function qt(e=""){const t=e?` value="${De(e)}"`:"",i=e?"":"display:none;";return`\n
\n \n \n
\n `}function jt(e,t,i,s,o,a,l){const c=t.entities?.power,d=c?i.states[c]:null,h=d&&parseFloat(d.state)||0,p=t.entities?.switch,u=p?i.states[p]:null,g=u?"on"===u.state:(d?.attributes?.relay_state||t.relay_state)===r,f=t.breaker_rating_a,v=f?`${Math.round(f)}A`:"",m=De(t.name||n("grid.unknown")),b=Ke(s),y="current"===b.entityRole;let w;if(g)if(y){const e=t.entities?.current,n=e?i.states[e]:null,s=n&&parseFloat(n.state)||0;w=`${b.format(s)}A`}else w=`${We(h)}${Ve(h)}`;else w="";const x=a||"unknown";let $="";if("unknown"!==x){const e=_[x]??_.unknown??{icon:"mdi:help",color:"#999",label:()=>"Unknown"};$=e.icon2?`\n \n \n `:e.textLabel?`\n \n ${e.textLabel}\n `:``}let S="";if(null!=o?.utilization_pct){const e=o.utilization_pct;S=`${Math.round(e)}%`}const C=g?'ON':'OFF';return`\n
\n ${v?`${v}`:""}\n ${m}\n ${$}\n ${S}\n ${C}\n \n ${w}\n \n \n
\n `}function Ut(e,t,n,i,s,o){const a=nt(e,t,0,"1","single",n,i,s,o,!0);return`
${a}
`}function Gt(e){return`
${De(e)}
`}function Vt(e,t,n){const i=e.entities?.switch,s=i?t.states[i]:null,o=e.entities?.power,a=o?t.states[o]:null,l=s?"on"===s.state:(a?.attributes?.relay_state||e.relay_state)===r;let c;if("current"===(n.chart_metric||"power")){const n=e.entities?.current,i=n?t.states[n]:null;c=i?Math.abs(parseFloat(i.state)||0):0}else c=a?Math.abs(parseFloat(a.state)||0):0;return{isOn:l,value:c}}function Wt(e,t){if(e.always_on)return"always_on";const n=e.entities?.select,i=n?t.states[n]:null;return i?i.state:"unknown"}function Bt(e,t,n,i){const s=Vt(e,n,i),o=Vt(t,n,i);return s.isOn&&!o.isOn?-1:!s.isOn&&o.isOn?1:o.value-s.value}function Qt(e,t,n){return e.sort((e,i)=>Bt(e[1],i[1],t,n))}function Jt(e){return e.entities?.current??e.entities?.power??""}class Xt{constructor(e){this._expandedUuids=new Set,this._searchQuery="",this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null,this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null,this._viewName=null,this._ctrl=e}setInitialExpansion(e){this._expandedUuids=new Set(e)}setInitialSearchQuery(e){this._searchQuery=e}setViewName(e){this._viewName=e}renderActivityView(e,t,n,i,s,o){this._unbindEvents(),this._hass=t,this._topology=n,this._config=i,this._monitoringStatus=s;const a=Qt(Object.entries(n.circuits),t,i);let r=o+qt(this._searchQuery);r+='
';for(const[e,n]of a){const o=et(s,Jt(n)),a=Wt(n,t),l=this._expandedUuids.has(e);r+=jt(e,n,t,i,o,a,l),l&&(r+=Ut(e,n,t,i,o,a))}r+="
",r+="",e.innerHTML=r;const l=e.querySelector("span-side-panel");l&&(l.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}renderAreaView(e,t,i,s,o,a){this._unbindEvents(),this._hass=t,this._topology=i,this._config=s,this._monitoringStatus=o;const r=n("list.unassigned_area"),l=new Map;for(const[e,t]of Object.entries(i.circuits)){const n=t.area??r,i=l.get(n);i?i.push([e,t]):l.set(n,[[e,t]])}const c=[...l.keys()].sort((e,t)=>e===r?1:t===r?-1:e.localeCompare(t));let d=a+qt(this._searchQuery);d+='
';for(const e of c){const n=l.get(e);if(!n)continue;const i=Qt(n,t,s);d+=Gt(e);for(const[e,n]of i){const i=et(o,Jt(n)),a=Wt(n,t),r=this._expandedUuids.has(e);d+=jt(e,n,t,s,i,a,r),r&&(d+=Ut(e,n,t,s,i,a))}}d+="
",d+="",e.innerHTML=d;const h=e.querySelector("span-side-panel");h&&(h.hass=t),this._bindEvents(e),this._searchQuery&&this._applyFilter(e),this._ctrl.updateDOM(e)}updateCollapsedRows(e,t,n,i){const s=Ke(i),o="current"===s.entityRole,a=e.querySelectorAll(".list-row[data-row-uuid]");for(const e of a){const a=e.dataset.rowUuid;if(!a)continue;const r=n.circuits[a];if(!r)continue;const{isOn:l,value:c}=Vt(r,t,i),d=e.querySelector(".list-power-value");if(d)if(l)if(o)d.innerHTML=`${s.format(c)}A`;else{const e=r.entities?.power,n=e?t.states[e]:null,i=n&&parseFloat(n.state)||0;d.innerHTML=`${We(i)}${Ve(i)}`}else d.innerHTML="";const h=e.querySelector(".list-status-badge");h&&(h.textContent=l?"ON":"OFF",h.classList.toggle("list-status-on",l),h.classList.toggle("list-status-off",!l)),e.classList.toggle("circuit-off",!l)}!function(e,t,n,i){const s=e.querySelector(".list-view");if(s)for(const e of function(e,t){let n={anchor:null,units:[]};const i=[n],s=[...e.children];for(let e=0;eBt(e.circuit,n.circuit,t,i));if(!n.some((t,n)=>t.uuid!==e.units[n].uuid))continue;let o=e.anchor;for(const e of n)o?o.after(e.row):s.prepend(e.row),o=e.row,e.expanded&&(o.after(e.expanded),o=e.expanded)}}(e,t,n,i)}stop(){this._unbindEvents(),null===this._viewName&&(this._expandedUuids.clear(),this._searchQuery=""),this._hass=null,this._topology=null,this._config=null,this._monitoringStatus=null}_dispatchFavoritesViewState(){if(!this._viewName||!this._container)return;const e={view:this._viewName,expanded:[...this._expandedUuids],searchQuery:this._searchQuery};this._container.dispatchEvent(new CustomEvent("favorites-view-state-changed",{detail:e,bubbles:!0,composed:!0}))}_bindEvents(e){this._container=e,this._clickHandler=t=>{const n=t.target;if(!n)return;const i=n.closest(".list-expand-toggle");if(i){const e=i.dataset.expandUuid;return void(e&&this._toggleExpand(e))}if(n.closest(".gear-icon"))return void this._ctrl.onGearClick(t,e);if(n.closest(".toggle-pill"))return void this._ctrl.onToggleClick(t,e);if(n.closest(".list-search-clear")){const t=e.querySelector(".list-search");return void(t&&(t.value="",t.dispatchEvent(new Event("input",{bubbles:!0}))))}const s=n.closest(".unit-btn");if(s){const t=s.dataset.unit;t&&e.dispatchEvent(new CustomEvent("unit-changed",{detail:t,bubbles:!0,composed:!0}))}},this._inputHandler=t=>{const n=t.target;n&&n.classList.contains("list-search")&&(this._searchQuery=n.value.toLowerCase(),this._applyFilter(e),this._dispatchFavoritesViewState())},this._graphSettingsHandler=()=>{this._ctrl.onGraphSettingsChanged(e).then(()=>{this._ctrl.updateDOM(e)}).catch(()=>{})},e.addEventListener("click",this._clickHandler),e.addEventListener("input",this._inputHandler),e.addEventListener("graph-settings-changed",this._graphSettingsHandler)}_unbindEvents(){this._container&&(this._clickHandler&&this._container.removeEventListener("click",this._clickHandler),this._inputHandler&&this._container.removeEventListener("input",this._inputHandler),this._graphSettingsHandler&&this._container.removeEventListener("graph-settings-changed",this._graphSettingsHandler)),this._container=null,this._clickHandler=null,this._inputHandler=null,this._graphSettingsHandler=null}_applyFilter(e){const t=e.querySelector(".list-search-clear");t&&(t.style.display=this._searchQuery?"":"none");const n=e.querySelectorAll(".list-row[data-row-uuid]");for(const t of n){const n=t.querySelector(".list-circuit-name"),i=(n?.textContent?.toLowerCase()??"").includes(this._searchQuery);t.style.display=i?"":"none";const s=t.dataset.rowUuid;if(s){const t=e.querySelector(`.list-expanded-content[data-expanded-uuid="${s}"]`);t&&(t.style.display=i?"":"none")}}const i=e.querySelectorAll(".area-header");for(const e of i){let t=!1,n=e.nextElementSibling;for(;n&&!n.classList.contains("area-header");){if(n.classList.contains("list-row")&&"none"!==n.style.display){t=!0;break}n=n.nextElementSibling}e.style.display=t?"":"none"}}_toggleExpand(e){if(!(this._container&&this._hass&&this._topology&&this._config))return;const t=this._container.querySelector(`.list-row[data-row-uuid="${e}"]`),n=this._container.querySelector(`.list-expand-toggle[data-expand-uuid="${e}"]`);if(t){if(this._expandedUuids.has(e)){this._expandedUuids.delete(e);const i=this._container.querySelector(`.list-expanded-content[data-expanded-uuid="${e}"]`);i&&i.remove(),n&&n.classList.remove("expanded"),t.classList.remove("list-row-expanded")}else{this._expandedUuids.add(e);const i=this._topology.circuits[e];if(!i)return;const s=et(this._monitoringStatus,Jt(i)),o=Wt(i,this._hass),a=Ut(e,i,this._hass,this._config,s,o);t.insertAdjacentHTML("afterend",a),n&&n.classList.add("expanded"),t.classList.add("list-row-expanded"),this._ctrl.updateDOM(this._container)}this._dispatchFavoritesViewState()}}}function Kt(e,t){return`${e}|${t}`}class Zt{async build(e,t,n){const i=new Map;for(const e of n)i.set(e.id,e);const s=[];for(const[n,o]of Object.entries(t)){if(!((o?.circuits?.length??0)>0||(o?.sub_devices?.length??0)>0))continue;const t=i.get(n);t&&s.push((async()=>{try{const i=await je(e,n);return{panelDeviceId:n,panel:t,topology:i.topology}}catch(e){return console.warn("SPAN Panel: favorites topology fetch failed",n,e),{panelDeviceId:n,panel:t,topology:null}}})())}const o=(await Promise.all(s)).filter(e=>null!==e.topology),a=o.length>1,r={},l={},c={},d=new Set;for(const{panelDeviceId:e,panel:n,topology:i}of o){if(!i)continue;const s=n.config_entries?.[0]??null;s&&d.add(s);const o=n.name_by_user??n.name??i.device_name??"",h=t[e],p=h?.circuits??[],u=h?.sub_devices??[];for(const t of p){const n=i.circuits?.[t];if(!n)continue;const l=Kt(e,t),d=a&&o?`${o} · ${n.name}`:n.name;r[l]={...n,name:d},c[l]={panelDeviceId:e,kind:"circuit",targetId:t,configEntryId:s}}for(const t of u){const n=i.sub_devices?.[t];if(!n)continue;const r=Kt(e,t),d=a&&o&&n.name?`${o} · ${n.name}`:n.name??t;l[r]={...n,name:d},c[r]={panelDeviceId:e,kind:"sub_device",targetId:t,configEntryId:s}}}return{topology:{circuits:r,sub_devices:l,panel_entities:{},device_name:"",_favoriteRefs:c},entryIds:Array.from(d)}}}const Yt="favorites",en="span_panel_favorites_view_state";function tn(e){try{localStorage.setItem(en,JSON.stringify(e))}catch{}}let nn=class extends $e{constructor(){super(...arguments),this.narrow=!1,this._panels=[],this._selectedPanelId=null,this._activeTab="dashboard",this._discovered=!1,this._discoveryError=null,this._favorites={},this._favoritesViewState={expanded:{activity:[],area:[]}},this._dashboardTab=new It,this._monitoringTab=new Ot,this._listDashCtrl=new Mt,this._listCtrl=new Xt(this._listDashCtrl),this._favCache=new He,this._favCtrl=new Zt,this._favoritesMonitoringTabs=new Map,this._refreshSeq=0,this._areaUnsub=null,this._onVisibilityChange=null,this._onFavoritesChanged=null,this._deviceRegistryUnsub=null}connectedCallback(){super.connectedCallback(),this._onVisibilityChange=()=>{"visible"===document.visibilityState&&this._discovered&&this.hass&&this._scheduleTabRender()},document.addEventListener("visibilitychange",this._onVisibilityChange),this._onFavoritesChanged=()=>{this._refreshFavorites()},document.addEventListener(Ne,this._onFavoritesChanged),this._subscribeDeviceRegistry()}disconnectedCallback(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear(),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._onVisibilityChange&&(document.removeEventListener("visibilitychange",this._onVisibilityChange),this._onVisibilityChange=null),this._onFavoritesChanged&&(document.removeEventListener(Ne,this._onFavoritesChanged),this._onFavoritesChanged=null),this._unsubscribeDeviceRegistry(),super.disconnectedCallback()}firstUpdated(){this.hass&&!this._discovered&&this._discoverPanels()}updated(e){if(e.has("hass")){const t=e.get("hass");this._dashboardTab.hass=this.hass,this._listDashCtrl.hass=this.hass,this._discovered?this.shadowRoot.getElementById("tab-content")||this._scheduleTabRender():this._discoverPanels(),!t&&this.hass&&this._subscribeDeviceRegistry()}if(this._discovered&&(e.has("_discovered")||e.has("_activeTab")||e.has("_selectedPanelId")||e.has("_chartMetric"))&&this._scheduleTabRender(),this._discovered&&(e.has("_panels")||e.has("_selectedPanelId"))){const e=this.shadowRoot?.getElementById("panel-select");e&&null!==this._selectedPanelId&&e.value!==this._selectedPanelId&&(e.value=this._selectedPanelId)}if(e.has("hass")&&this._discovered&&("activity"===this._activeTab||"area"===this._activeTab)){const e=this.shadowRoot.getElementById("tab-content"),t=this._listDashCtrl.topology;if(e&&t){this._listCtrl.updateCollapsedRows(e,this.hass,t,this._buildDashboardConfig());const n=e.querySelector("span-side-panel");n&&(n.hass=this.hass)}}}setConfig(e){}render(){var n,i,s;return n=this.hass?.language,e=n&&t[n]?n:"en",this.hass?this._discovered?oe`
@@ -59,7 +59,7 @@ const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce
-
${Te((n=this._buildTabList(),s=this._activeTab,`
${n.map(e=>``).join("")}
`))}
+
${Te((i=this._buildTabList(),s=this._activeTab,`
${i.map(e=>``).join("")}
`))}
@@ -95,7 +95,7 @@ const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce
${"Loading…"}
- `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===Zt}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const i=t.dataset.tab;i&&i!==this._activeTab&&(this._activeTab=i,this._isFavoritesView&&"dashboard"!==i&&(this._favoritesViewState.activeTab=i,ei(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const i=this._favoritesViewState;i.activeTab=t.view;const n=this._listDashCtrl.topology?.circuits??{};i.expanded[t.view]=t.expanded.filter(e=>e in n),i.searchQuery=t.searchQuery,ei(i)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==Zt).map(e=>e.id)),i=new Set(e.map(e=>e.id));if((t.size!==i.size||[...t].some(e=>!i.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(Yt);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const i=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(i.activity)?i.activity:[],area:Array.isArray(i.area)?i.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===Zt){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Fe(t))return e;return[{id:Zt,name:i("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){const e=++this._refreshSeq;this._favCache.invalidate();const t=await this._loadFavorites();if(e!==this._refreshSeq)return;const i=this._selectedPanelId===Zt;this._favorites=t;const n=this._panels.filter(e=>e.id!==Zt);if(this._panels=this._buildPanelList(n,t),i&&!Fe(t)){!function(){try{localStorage.removeItem(Yt)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=n[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:i("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:i("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:i("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:i("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return Ue(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=function(e){let t=0;for(const i of Object.values(e))t+=(i.circuits?.length??0)+(i.sub_devices?.length??0);return t}(this._favorites),t=i(1===e?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(e)),n="current"===(this._chartMetric||"power");return`\n
\n
${De(i("panel.favorites"))}
\n
${De(t)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),i=this._panels.find(e=>e.id===this._selectedPanelId),n=i?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,n);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),i=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),n=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,n,this.hass,i),await this._listDashCtrl.monitoringCache.fetch(this.hass,i),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,n):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,n,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message,e.appendChild(i)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),i=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),n=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,n,this.hass,i),await this._listDashCtrl.monitoringCache.fetch(this.hass,i),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,n):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,n,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,i){if(!e.connection)return()=>{};const n=async()=>{try{const n=new Map;for(const[e,i]of Object.entries(t.circuits))n.set(e,i.area);await qe(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==n.get(e))return void i()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(n,"entity_registry_updated"),e.connection.subscribeEvents(n,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message,e.appendChild(i)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),i=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,i??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==Zt),n=await this._favCtrl.build(this.hass,this._favorites,t),s=n.topology,o=n.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=i("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,n.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ut(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message,e.appendChild(i)}}async _renderFavoritesMonitoring(e,t,i){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const n=document.createElement("div");n.className="favorites-monitoring-stack",e.appendChild(n);const s=new Map;for(const e of i){const t=e.config_entries?.[0];t&&s.set(t,e)}const o=new Map;for(const e of t){const t=s.get(e),i=document.createElement("div");i.className="favorites-monitoring-block",i.style.marginBottom="24px";const a=document.createElement("h2");a.style.margin="8px 0 12px",a.style.fontSize="1em",a.textContent=t?.name_by_user??t?.name??e,i.appendChild(a);const r=document.createElement("div");i.appendChild(r),n.appendChild(i);const l=new Ot;o.set(e,l);try{await l.render(r,this.hass,e)}catch(t){console.warn("SPAN Panel: favorites monitoring render failed",e,t);const i=document.createElement("p");i.style.color="var(--error-color)",i.textContent=t.message??String(t),r.appendChild(i)}}this._favoritesMonitoringTabs=o}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};ti.styles=((e,...t)=>{const i=1===e.length?e[0]:t.reduce((t,i,n)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[n+1],e[0]);return new x(i,e,y)})` + `}_onPanelChange(e){const t=e.target;this._selectedPanelId=t.value,localStorage.setItem("span_panel_selected",t.value),this._isFavoritesView&&"dashboard"===this._activeTab&&(this._activeTab="activity"),this._areaUnsub&&(this._areaUnsub(),this._areaUnsub=null),this._scheduleTabRender()}get _isFavoritesView(){return this._selectedPanelId===Yt}_onTabClick(e){const t=e.target.closest(".shared-tab");if(!t)return;const n=t.dataset.tab;n&&n!==this._activeTab&&(this._activeTab=n,this._isFavoritesView&&"dashboard"!==n&&(this._favoritesViewState.activeTab=n,tn(this._favoritesViewState)),this._scheduleTabRender())}_onTabContentClick(e){const t=e.target.closest(".unit-btn");if(t){const e=t.dataset.unit;if(!e||e===this._chartMetric)return;return this._chartMetric=e,localStorage.setItem("span_panel_metric",e),void("dashboard"===this._activeTab&&this._scheduleTabRender())}}_onSidePanelClosed(){if("dashboard"===this._activeTab){const e=this._dashboardTab._ctrl;e.monitoringCache.invalidate(),e.graphSettingsCache.invalidate()}}_onUnitChanged(e){const t=e.detail;t&&t!==this._chartMetric&&(this._chartMetric=t,localStorage.setItem("span_panel_metric",t),this._scheduleTabRender())}_onGraphSettingsChanged(){if("dashboard"===this._activeTab){const e=this.shadowRoot.getElementById("tab-content");if(e){this._dashboardTab._ctrl.onGraphSettingsChanged(e)}}}_onNavigateTab(e){const t=e.detail;t&&(this._activeTab=t,this._scheduleTabRender())}_onFavoritesViewStateChangedEvent(e){if(!this._isFavoritesView)return;const t=e.detail;if(!t)return;const n=this._favoritesViewState;n.activeTab=t.view;const i=this._listDashCtrl.topology?.circuits??{};n.expanded[t.view]=t.expanded.filter(e=>e in i),n.searchQuery=t.searchQuery,tn(n)}_subscribeDeviceRegistry(){!this._deviceRegistryUnsub&&this.hass?.connection&&(this._deviceRegistryUnsub=this.hass.connection.subscribeEvents(()=>this._refreshPanels(),"device_registry_updated"))}_unsubscribeDeviceRegistry(){this._deviceRegistryUnsub&&(this._deviceRegistryUnsub.then(e=>e()),this._deviceRegistryUnsub=null)}async _refreshPanels(){if(!this.hass||!this._discovered)return;const e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id),t=new Set(this._panels.filter(e=>e.id!==Yt).map(e=>e.id)),n=new Set(e.map(e=>e.id));if((t.size!==n.size||[...t].some(e=>!n.has(e)))&&(this._panels=this._buildPanelList(e,this._favorites),!this._panels.some(e=>e.id===this._selectedPanelId)&&this._panels.length>0)){const t=e[0];t&&(this._selectedPanelId=t.id,localStorage.setItem("span_panel_selected",this._selectedPanelId))}}async _discoverPanels(){if(!this.hass)return;let e;try{e=(await this.hass.callWS({type:"config/device_registry/list"})).filter(e=>e.identifiers?.some(e=>e[0]===a)&&!e.via_device_id)}catch(e){return console.error("SPAN Panel: device discovery failed",e),void(this._discoveryError=`Discovery failed: ${e.message??e}`)}this._favorites=await this._loadFavorites(),this._panels=this._buildPanelList(e,this._favorites),this._favoritesViewState=function(){try{const e=localStorage.getItem(en);if(!e)return{expanded:{activity:[],area:[]}};const t=JSON.parse(e);if(!t||"object"!=typeof t)return{expanded:{activity:[],area:[]}};const n=t.expanded??{activity:[],area:[]};return{activeTab:t.activeTab,expanded:{activity:Array.isArray(n.activity)?n.activity:[],area:Array.isArray(n.area)?n.area:[]},searchQuery:"string"==typeof t.searchQuery?t.searchQuery:void 0}}catch{return{expanded:{activity:[],area:[]}}}}(),this._discoveryError=null,this._discovered=!0;const t=localStorage.getItem("span_panel_selected");if(t&&this._panels.some(e=>e.id===t)?this._selectedPanelId=t:e.length>0&&(this._selectedPanelId=e[0].id),this._selectedPanelId===Yt){const e=this._favoritesViewState.activeTab;"activity"===e||"area"===e||"monitoring"===e?this._activeTab=e:"dashboard"===this._activeTab&&(this._activeTab="activity")}this._chartMetric=localStorage.getItem("span_panel_metric")||"power"}_buildPanelList(e,t){if(!Fe(t))return e;return[{id:Yt,name:n("panel.favorites"),model:"__favorites__"},...e]}async _loadFavorites(){if(!this.hass)return{};try{return await this._favCache.fetch(this.hass)}catch(e){return console.warn("SPAN Panel: favorites fetch failed",e),{}}}async _refreshFavorites(){const e=++this._refreshSeq;this._favCache.invalidate();const t=await this._loadFavorites();if(e!==this._refreshSeq)return;const n=this._selectedPanelId===Yt;this._favorites=t;const i=this._panels.filter(e=>e.id!==Yt);if(this._panels=this._buildPanelList(i,t),n&&!Fe(t)){!function(){try{localStorage.removeItem(en)}catch{}}(),this._favoritesViewState={expanded:{activity:[],area:[]}};const e=i[0];e?(this._selectedPanelId=e.id,localStorage.setItem("span_panel_selected",e.id)):this._selectedPanelId=null}else this._isFavoritesView?this._scheduleTabRender():this._applyPanelFavorites()}_buildTabList(){const e=[];return this._isFavoritesView||e.push({id:"dashboard",label:n("tab.by_panel"),icon:"mdi:view-dashboard"}),e.push({id:"activity",label:n("tab.by_activity"),icon:"mdi:sort-descending"},{id:"area",label:n("tab.by_area"),icon:"mdi:home-group"},{id:"monitoring",label:n("tab.monitoring"),icon:"mdi:monitor-eye"}),e}_buildCurrentPanelHeaderHTML(e,t){return Ue(e,t,{showSwitches:!1})}_buildFavoritesSummaryHTML(){const e=function(e){let t=0;for(const n of Object.values(e))t+=(n.circuits?.length??0)+(n.sub_devices?.length??0);return t}(this._favorites),t=n(1===e?"panel.favorites_summary_one":"panel.favorites_summary_many").replace("{circuits}",String(e)),i="current"===(this._chartMetric||"power");return`\n
\n
${De(n("panel.favorites"))}
\n
${De(t)}
\n
\n \n \n
\n
\n `}_buildDashboardConfig(){return{chart_metric:this._chartMetric,history_minutes:5,show_panel:!0,show_battery:!0,show_evse:!0}}async _scheduleTabRender(){await this.updateComplete,await this._renderTab()}async _renderTab(){this._dashboardTab.stop(),this._monitoringTab.stop(),this._listCtrl.stop(),this._listDashCtrl.stopIntervals();for(const e of this._favoritesMonitoringTabs.values())e.stop();this._favoritesMonitoringTabs.clear();const e=this.shadowRoot.getElementById("tab-content");if(e)if(this._isFavoritesView)await this._renderFavoritesTab(e);else switch(this._listDashCtrl.clearFavoriteRefs(),this._listCtrl.setViewName(null),this._applyPanelFavorites(),this._activeTab){case"dashboard":{e.innerHTML="";const t=this._buildDashboardConfig(),n=this._panels.find(e=>e.id===this._selectedPanelId),i=n?.config_entries?.[0]??null;await this._dashboardTab.render(e,this.hass,this._selectedPanelId??"",t,i);break}case"activity":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderActivityView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"area":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;try{const t=await je(this.hass,this._selectedPanelId??void 0),i=this._buildDashboardConfig();this._listDashCtrl.init(t.topology,i,this.hass,n),await this._listDashCtrl.monitoringCache.fetch(this.hass,n),await this._listDashCtrl.fetchAndBuildHorizonMaps();const s=t.topology?this._buildCurrentPanelHeaderHTML(t.topology,i):"";this._listCtrl.renderAreaView(e,this.hass,t.topology,i,this._listDashCtrl.monitoringCache.status,s),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e),this._areaUnsub||async function(e,t,n){if(!e.connection)return()=>{};const i=async()=>{try{const i=new Map;for(const[e,n]of Object.entries(t.circuits))i.set(e,n.area);await qe(e,t);for(const[e,s]of Object.entries(t.circuits))if(s.area!==i.get(e))return void n()}catch(e){console.warn("[span-panel] area registry update failed:",e)}},[s,o]=await Promise.all([e.connection.subscribeEvents(i,"entity_registry_updated"),e.connection.subscribeEvents(i,"area_registry_updated")]);return()=>{s(),o()}}(this.hass,t.topology,()=>{"area"===this._activeTab&&this._scheduleTabRender()}).then(e=>{this._areaUnsub=e}).catch(()=>{})}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}break}case"monitoring":{e.innerHTML="";const t=this._panels.find(e=>e.id===this._selectedPanelId),n=t?.config_entries?.[0]??null;await this._monitoringTab.render(e,this.hass,n??void 0);break}}}async _renderFavoritesTab(e){if("dashboard"===this._activeTab&&(this._activeTab="activity"),e.innerHTML="",!this.hass)return;const t=this._panels.filter(e=>e.id!==Yt),i=await this._favCtrl.build(this.hass,this._favorites,t),s=i.topology,o=i.entryIds[0]??null,a=Object.keys(s.circuits).length>0,r=Object.keys(s.sub_devices??{}).length>0;if(!a&&!r){const t=document.createElement("p");return t.style.color="var(--secondary-text-color)",t.style.padding="24px",t.textContent=n("list.no_results"),void e.appendChild(t)}if(this._listDashCtrl.setFavoriteRefs(s._favoriteRefs),this._listDashCtrl.setPanelFavorites(null),"monitoring"===this._activeTab)return this._listCtrl.setViewName(null),void await this._renderFavoritesMonitoring(e,i.entryIds,t);const l=this._activeTab,c=new Set(Object.keys(s.circuits)),d=this._favoritesViewState.expanded[l].filter(e=>c.has(e));this._listCtrl.setViewName(l),this._listCtrl.setInitialExpansion(d),this._listCtrl.setInitialSearchQuery(this._favoritesViewState.searchQuery??"");const h=this._buildDashboardConfig();this._listDashCtrl.init(s,h,this.hass,o),await this._listDashCtrl.fetchAndBuildHorizonMaps();const p=this._buildFavoritesSummaryHTML()+(r?`
\n
${ut(s,this.hass,h)}
\n
`:"");try{"activity"===l?this._listCtrl.renderActivityView(e,this.hass,s,h,null,p):this._listCtrl.renderAreaView(e,this.hass,s,h,null,p),e.insertAdjacentHTML("afterbegin",``),await this._listDashCtrl.loadHistory(),this._listDashCtrl.updateDOM(e),this._listDashCtrl.startIntervals(e)}catch(t){const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message,e.appendChild(n)}}async _renderFavoritesMonitoring(e,t,n){if(!this.hass)return;e.insertAdjacentHTML("beforeend",this._buildFavoritesSummaryHTML());const i=document.createElement("div");i.className="favorites-monitoring-stack",e.appendChild(i);const s=new Map;for(const e of n){const t=e.config_entries?.[0];t&&s.set(t,e)}const o=new Map;for(const e of t){const t=s.get(e),n=document.createElement("div");n.className="favorites-monitoring-block",n.style.marginBottom="24px";const a=document.createElement("h2");a.style.margin="8px 0 12px",a.style.fontSize="1em",a.textContent=t?.name_by_user??t?.name??e,n.appendChild(a);const r=document.createElement("div");n.appendChild(r),i.appendChild(n);const l=new Ot;o.set(e,l);try{await l.render(r,this.hass,e)}catch(t){console.warn("SPAN Panel: favorites monitoring render failed",e,t);const n=document.createElement("p");n.style.color="var(--error-color)",n.textContent=t.message??String(t),r.appendChild(n)}}this._favoritesMonitoringTabs=o}_applyPanelFavorites(){if(!this._selectedPanelId||this._isFavoritesView)return this._listDashCtrl.setPanelFavorites(null),void this._dashboardTab.setPanelFavorites(null);const e=this._favorites[this._selectedPanelId],t={panelDeviceId:this._selectedPanelId,circuitUuids:new Set(e?.circuits??[]),subDeviceIds:new Set(e?.sub_devices??[])};this._listDashCtrl.setPanelFavorites(t),this._dashboardTab.setPanelFavorites(t)}};nn.styles=((e,...t)=>{const n=1===e.length?e[0]:t.reduce((t,n,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+e[i+1],e[0]);return new x(n,e,y)})` :host { color: var(--primary-text-color); } @@ -185,4 +185,4 @@ const Ce={attribute:!0,type:String,converter:N,reflect:!1,hasChanged:L},Ee=(e=Ce opacity: 1; border-bottom-color: var(--app-header-text-color, white); } - `,v([ke({attribute:!1})],ti.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],ti.prototype,"narrow",void 0),v([ze()],ti.prototype,"_panels",void 0),v([ze()],ti.prototype,"_selectedPanelId",void 0),v([ze()],ti.prototype,"_activeTab",void 0),v([ze()],ti.prototype,"_discovered",void 0),v([ze()],ti.prototype,"_discoveryError",void 0),v([ze()],ti.prototype,"_chartMetric",void 0),v([ze()],ti.prototype,"_favorites",void 0),ti=v([(e=>(t,i)=>{void 0!==i?i.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],ti),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let ii=!1;const ni=ti.prototype.connectedCallback;ti.prototype.connectedCallback=function(){ii=!0,ni.call(this)};const si=ti.prototype.disconnectedCallback;ti.prototype.disconnectedCallback=function(){ii=!1,si.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(ii||window.location.pathname.includes("span-panel")&&setTimeout(()=>{ii||location.reload()},200))}); + `,v([ke({attribute:!1})],nn.prototype,"hass",void 0),v([ke({type:Boolean,reflect:!0})],nn.prototype,"narrow",void 0),v([ze()],nn.prototype,"_panels",void 0),v([ze()],nn.prototype,"_selectedPanelId",void 0),v([ze()],nn.prototype,"_activeTab",void 0),v([ze()],nn.prototype,"_discovered",void 0),v([ze()],nn.prototype,"_discoveryError",void 0),v([ze()],nn.prototype,"_chartMetric",void 0),v([ze()],nn.prototype,"_favorites",void 0),nn=v([(e=>(t,n)=>{void 0!==n?n.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)})("span-panel")],nn),console.warn("%c SPAN-PANEL %c v0.9.3 ","background: var(--primary-color, #4dd9af); color: #000; font-weight: 700; padding: 2px 6px; border-radius: 4px 0 0 4px;","background: var(--secondary-background-color, #333); color: var(--primary-text-color, #fff); padding: 2px 6px; border-radius: 0 4px 4px 0;");let sn=!1;const on=nn.prototype.connectedCallback;nn.prototype.connectedCallback=function(){sn=!0,on.call(this)};const an=nn.prototype.disconnectedCallback;nn.prototype.disconnectedCallback=function(){sn=!1,an.call(this)},document.addEventListener("visibilitychange",()=>{"visible"===document.visibilityState&&(sn||window.location.pathname.includes("span-panel")&&setTimeout(()=>{sn||location.reload()},200))}); diff --git a/src/core/list-view-controller.ts b/src/core/list-view-controller.ts index bc42fe1..db526bb 100644 --- a/src/core/list-view-controller.ts +++ b/src/core/list-view-controller.ts @@ -44,14 +44,88 @@ function getSheddingPriority(circuit: Circuit, hass: HomeAssistant): string { return selectState ? selectState.state : "unknown"; } +function compareCircuits(a: Circuit, b: Circuit, hass: HomeAssistant, config: CardConfig): number { + const infoA = getCircuitSortInfo(a, hass, config); + const infoB = getCircuitSortInfo(b, hass, config); + if (infoA.isOn && !infoB.isOn) return -1; + if (!infoA.isOn && infoB.isOn) return 1; + return infoB.value - infoA.value; +} + function sortCircuitEntries(entries: [string, Circuit][], hass: HomeAssistant, config: CardConfig): [string, Circuit][] { - return entries.sort((a, b) => { - const infoA = getCircuitSortInfo(a[1], hass, config); - const infoB = getCircuitSortInfo(b[1], hass, config); - if (infoA.isOn && !infoB.isOn) return -1; - if (!infoA.isOn && infoB.isOn) return 1; - return infoB.value - infoA.value; - }); + return entries.sort((a, b) => compareCircuits(a[1], b[1], hass, config)); +} + +interface RowUnit { + row: HTMLElement; + expanded: HTMLElement | null; + uuid: string; + circuit: Circuit; +} + +interface RowGroup { + anchor: HTMLElement | null; + units: RowUnit[]; +} + +// Partition .list-view's direct children into groups. Activity view produces a +// single anchor-less group; area view produces one group per .area-header. +function partitionRowGroups(listView: HTMLElement, topology: PanelTopology): RowGroup[] { + let current: RowGroup = { anchor: null, units: [] }; + const groups: RowGroup[] = [current]; + const children = [...listView.children] as HTMLElement[]; + + for (let i = 0; i < children.length; ) { + const el = children[i]!; + if (el.classList.contains("area-header")) { + current = { anchor: el, units: [] }; + groups.push(current); + i++; + continue; + } + if (el.classList.contains("list-row")) { + const uuid = el.dataset.rowUuid; + const circuit = uuid ? topology.circuits[uuid] : undefined; + if (uuid && circuit) { + const next = children[i + 1]; + const expanded = next && next.classList.contains("list-expanded-content") && next.dataset.expandedUuid === uuid ? next : null; + current.units.push({ row: el, expanded, uuid, circuit }); + i += expanded ? 2 : 1; + continue; + } + } + i++; + } + + return groups; +} + +function reorderListRows(root: Element | ShadowRoot, hass: HomeAssistant, topology: PanelTopology, config: CardConfig): void { + const listView = root.querySelector(".list-view"); + if (!listView) return; + + for (const group of partitionRowGroups(listView, topology)) { + if (group.units.length < 2) continue; + + const sorted = [...group.units].sort((a, b) => compareCircuits(a.circuit, b.circuit, hass, config)); + + const changed = sorted.some((unit, j) => unit.uuid !== group.units[j]!.uuid); + if (!changed) continue; + + let after: Element | null = group.anchor; + for (const unit of sorted) { + if (after) { + after.after(unit.row); + } else { + listView.prepend(unit.row); + } + after = unit.row; + if (unit.expanded) { + after.after(unit.expanded); + after = unit.expanded; + } + } + } } function getCircuitEntityId(circuit: Circuit): string { @@ -261,6 +335,8 @@ export class ListViewController { // Toggle circuit-off class row.classList.toggle("circuit-off", !isOn); } + + reorderListRows(root, hass, topology, config); } stop(): void { From 458f2c4f0c5f86049150a677a8753277db6b52d6 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:00:34 -0700 Subject: [PATCH 07/97] docs: spec for compact expanded list rows --- ...04-15-favorites-expanded-compact-design.md | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-15-favorites-expanded-compact-design.md diff --git a/docs/superpowers/specs/2026-04-15-favorites-expanded-compact-design.md b/docs/superpowers/specs/2026-04-15-favorites-expanded-compact-design.md new file mode 100644 index 0000000..8e290a0 --- /dev/null +++ b/docs/superpowers/specs/2026-04-15-favorites-expanded-compact-design.md @@ -0,0 +1,186 @@ +# Favorites list view: compact expanded row + +Date: 2026-04-15 Repo: `span-card` (consumed by `span` HA integration) + +## Problem + +In the By-Area and By-Activity views, expanding a list row currently renders a full breaker "slot" above the chart: breaker badge, name, power/current value, +toggle pill, shedding icon, utilization %, gear. Every value in that expanded header is already shown in the collapsed list row beside it. The duplication +wastes vertical space that would be better used by the chart. + +The expanded view does contribute two things the collapsed row does not: a tappable on/off toggle, and a gear that opens the side panel for that circuit. + +## Goal + +Make the expanded list row show only the chart. Move the two unique controls into the collapsed row so they are always reachable without losing affordance. + +## Scope + +Applies to every invocation of `ListViewController` — both the Favorites full-page panel and the span-panel card dashboard's By-Area / By-Activity views. +Breaker grid view is not affected. + +## Design + +### 1. List row (collapsed) + +New layout, left to right: + +```text +[breaker badge] [name] [shedding] [util%] [ON/OFF badge*] [power] [gear] [chevron] +``` + +Changes versus today: + +- **Gear button** added between power and chevron. Uses the same `.gear-icon.circuit-gear` class and `data-uuid` attribute the breaker grid uses. Gear color + follows the existing "has custom overrides" rule (`MONITORING_COLORS.custom` vs `#555`). Clicks route to `DashboardController.onGearClick` via the existing + `.gear-icon` delegated handler — no new wiring. +- **ON/OFF badge becomes tappable** only when `circuit.is_user_controllable !== false && circuit.entities?.switch`. When tappable the badge gains a + `list-status-toggle` class (adds `cursor: pointer`, hover state). When not tappable, the badge renders exactly as it does today — static. +- Tappable badge clicks route to `DashboardController.onToggleClick`. Event delegation in `list-view-controller.ts` extends its toggle selector to + `.toggle-pill, .list-status-toggle`. + +The existing `list-status-on` / `list-status-off` classes continue to control badge color. + +OFF circuits continue to render an empty power cell. + +### 2. Expanded content (chart-only) + +New helper in `core/list-renderer.ts`: + +```ts +export function buildExpandedChartHTML( + uuid: string, + circuit: Circuit, + hass: HomeAssistant, + config: CardConfig, + monitoringInfo: MonitoringPointInfo | null +): string; +``` + +Produces: + +```html +
+
+
+
+
+``` + +Where `{state-classes}` is a space-joined string of any of `circuit-off`, `circuit-producer`, `circuit-alert`, `circuit-custom-monitoring` — produced by a new +shared helper (see §3). + +`buildExpandedCircuitHTML` is deleted. All three call sites in `list-view-controller.ts` switch to `buildExpandedChartHTML`. + +Preserving the `.circuit-slot[data-uuid]` wrapper is intentional: `DashboardController.updateDOM` walks that selector to attach charts to their +`.chart-container`. Zero changes required in the chart-attachment pipeline. + +The `circuit-chart-only` class is a CSS-only marker (tight padding, full-bleed chart). It does not gate any logic. + +### 3. Shared state-class helper + +Extract into `core/list-renderer.ts` (or a new `core/circuit-state.ts` — picked during implementation based on import cleanliness): + +```ts +export function getCircuitStateClasses(circuit: Circuit, monitoringInfo: MonitoringPointInfo | null, isOn: boolean, isProducer: boolean): string; +``` + +Returns a class string containing any of: `circuit-off`, `circuit-producer`, `circuit-alert`, `circuit-custom-monitoring`. + +`grid-renderer.ts` `renderCircuitSlot` adopts this same helper so grid and list stay in sync. This is the only factoring change in `renderCircuitSlot`. + +### 4. Event handling in `ListViewController` + +`_bindEvents` changes: + +- Toggle selector widens: `target.closest(".toggle-pill, .list-status-toggle")`. +- Gear selector unchanged (`.gear-icon`). The list-row gear uses the same class, so it is already covered. + +`updateCollapsedRows` additions: + +- When a circuit flips, it already updates badge text and `list-status-on`/`list-status-off`. Also ensure `list-status-toggle` is added/removed if + controllability changes (rare, but cheap). +- Sort logic and expanded-row pairing in `partitionRowGroups` / `reorderListRows` unchanged. + +`_toggleExpand`, `_applyFilter`, favorites state persistence (`FAVORITES_VIEW_STATE_CHANGED_EVENT`, `_expandedUuids`, `_searchQuery`) all unchanged. + +### 5. CSS (`card/card-styles.ts`) + +Add: + +```css +.list-row .gear-icon { + background: transparent; + border: none; + padding: 2px; + cursor: pointer; + color: #555; + display: inline-flex; + align-items: center; +} +.list-row .gear-icon:hover { + color: var(--primary-text-color); +} + +.list-status-badge.list-status-toggle { + cursor: pointer; + user-select: none; +} +.list-status-badge.list-status-toggle:hover { + filter: brightness(1.15); +} + +.list-expanded-content { + padding: 0; +} + +.circuit-slot.circuit-chart-only { + border: none; + padding: 8px 12px; + margin: 0; +} +``` + +Chart height within `.circuit-chart-only .chart-container` must match today's expanded chart height. Exact value is pinned during implementation by reading the +current rule; noted as a verification point. + +Remove the now-redundant `.list-expanded-content .circuit-slot { border: none; margin: 0; }` override. + +Existing `.circuit-alert` / `.circuit-custom-monitoring` rules continue to style `.circuit-slot` and therefore also apply to `.circuit-slot.circuit-chart-only` +— alert/custom border signaling is preserved on the expanded chart. + +## Files touched + +- `src/core/list-renderer.ts` — add `buildExpandedChartHTML`, update `buildListRowHTML` (gear, tappable badge), extract `getCircuitStateClasses`, delete + `buildExpandedCircuitHTML`. +- `src/core/grid-renderer.ts` — adopt `getCircuitStateClasses` in `renderCircuitSlot`. +- `src/core/list-view-controller.ts` — swap renderer at three sites; widen toggle selector; badge-class upkeep in `updateCollapsedRows`. +- `src/card/card-styles.ts` — gear rules, tappable badge rules, chart-only slot rules; remove redundant override. + +Not touched: `panel/span-panel.ts`, `card/span-panel-card.ts`, `core/dashboard-controller.ts`, `core/header-renderer.ts`, `core/favorites-*`, +`core/area-resolver.ts`, `core/history-loader.ts`, `core/graph-settings.ts`, chart module, side panel. + +## Verification points for implementation + +1. Confirm `DashboardController.onToggleClick` resolves `data-uuid` from an ancestor that reaches `.list-row`. If today the lookup walks only to + `.circuit-slot`, widen to `.circuit-slot, .list-row`. +2. Enumerate tests that assert presence of `.circuit-header` / `.circuit-status` inside expanded content; update them to the new chart-only structure. +3. Measure current `.chart-container` height in an expanded list row and match it in the new rule so the change does not shrink the chart. + +## Manual test plan + +- Expand rows in By-Activity and By-Area, in both Favorites and the regular dashboard card. +- Confirm header/status no longer duplicate list-row info. +- Tap the ON/OFF badge on a controllable circuit: state flips, row re-sorts, badge color updates. +- Tap the ON/OFF badge on a non-controllable (PV) circuit: nothing happens, no hover cursor. +- Tap the list-row gear: side panel opens for that circuit. +- Trigger a monitoring alert: expanded chart area shows the alert border. +- Reload the Favorites page: expansion state restores; chart remounts; no layout jumps. +- Breaker grid view: unchanged. + +## Out of scope + +- Adding alert/error visuals to the collapsed list row. +- Restyling the side panel or breaker-grid view. +- Any change to the tab bar, monitoring tabs, or settings. +- Changes to `span` HA integration backend code. From 4f891e581df06a5b8b55da5f216be0b86dab2667 Mon Sep 17 00:00:00 2001 From: cayossarian <23534755+cayossarian@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:08:05 -0700 Subject: [PATCH 08/97] docs: implementation plan for compact expanded list rows --- .../2026-04-15-favorites-expanded-compact.md | 865 ++++++++++++++++++ 1 file changed, 865 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-15-favorites-expanded-compact.md diff --git a/docs/superpowers/plans/2026-04-15-favorites-expanded-compact.md b/docs/superpowers/plans/2026-04-15-favorites-expanded-compact.md new file mode 100644 index 0000000..f74be39 --- /dev/null +++ b/docs/superpowers/plans/2026-04-15-favorites-expanded-compact.md @@ -0,0 +1,865 @@ +# Favorites list view — compact expanded row — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan +> task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** In By-Activity and By-Area list views, expanding a row should reveal only the chart; the two unique controls (gear and ON/OFF toggle) move onto the +always-visible list row. + +**Architecture:** A new `buildExpandedChartHTML` renderer replaces the duplicative `buildExpandedCircuitHTML`. The list row gains a gear button and a tappable +ON/OFF badge. A small shared `getCircuitStateClasses` helper keeps state-visualization classes consistent between the grid and the new chart-only expanded slot. + +**Tech Stack:** TypeScript, Lit (lightly used here — this card uses manual innerHTML), Vitest, Rollup, CSS-in-JS via tagged template literals. + +**Spec:** `docs/superpowers/specs/2026-04-15-favorites-expanded-compact-design.md` + +--- + +## File map + +**Create:** + +- `src/core/circuit-state.ts` — shared `getCircuitStateClasses` helper. +- `tests/circuit-state.test.ts` — unit tests for the helper. + +**Modify:** + +- `src/core/grid-renderer.ts` — adopt `getCircuitStateClasses`. +- `src/core/list-renderer.ts` — add `buildExpandedChartHTML`, update `buildListRowHTML`, delete `buildExpandedCircuitHTML`. +- `src/core/list-view-controller.ts` — swap renderer calls, widen toggle selector, extend `updateCollapsedRows`. +- `src/core/dashboard-controller.ts` — widen `onToggleClick` pill selector to include `list-status-toggle`. +- `src/card/card-styles.ts` — add gear/badge/chart-only rules. + +**Test:** + +- `tests/circuit-state.test.ts` (new, above). +- `tests/list-renderer.test.ts` (new — covers both renderers' new output shape). + +**Sync (post-build):** + +- `../../../HA/span/custom_components/span_panel/frontend/dist/` — via `scripts/build-frontend.sh` in the HA integration, or the `sync-frontend` skill. + +--- + +## Task 1: Add shared `getCircuitStateClasses` helper + +Extracts the `circuit-off` / `circuit-producer` / `circuit-alert` / `circuit-custom-monitoring` class logic that `renderCircuitSlot` computes inline today. Grid +and list will both call this so they stay in sync. + +**Files:** + +- Create: `src/core/circuit-state.ts` +- Create: `tests/circuit-state.test.ts` + +- [ ] **Step 1: Write the failing test** + +Create `tests/circuit-state.test.ts`: + +```ts +import { describe, it, expect } from "vitest"; +import { getCircuitStateClasses } from "../src/core/circuit-state.js"; +import type { Circuit, MonitoringPointInfo } from "../src/types.js"; + +const baseCircuit: Circuit = { name: "Test" }; + +describe("getCircuitStateClasses", () => { + it("returns empty string when circuit is on, not producer, no monitoring info", () => { + expect(getCircuitStateClasses(baseCircuit, null, true, false)).toBe(""); + }); + + it("adds circuit-off when isOn is false", () => { + expect(getCircuitStateClasses(baseCircuit, null, false, false)).toBe("circuit-off"); + }); + + it("adds circuit-producer when isProducer is true", () => { + expect(getCircuitStateClasses(baseCircuit, null, true, true)).toBe("circuit-producer"); + }); + + it("adds both when off and producer", () => { + const result = getCircuitStateClasses(baseCircuit, null, false, true); + expect(result).toContain("circuit-off"); + expect(result).toContain("circuit-producer"); + }); + + it("adds circuit-alert when monitoringInfo indicates alert", () => { + const info: MonitoringPointInfo = { utilization_pct: 95, over_threshold_since: "2024-01-01T00:00:00Z" }; + const result = getCircuitStateClasses(baseCircuit, info, true, false); + expect(result).toContain("circuit-alert"); + }); + + it("adds circuit-custom-monitoring when continuous_threshold_pct is set", () => { + const info: MonitoringPointInfo = { continuous_threshold_pct: 80 }; + const result = getCircuitStateClasses(baseCircuit, info, true, false); + expect(result).toContain("circuit-custom-monitoring"); + }); + + it("handles all classes together", () => { + const info: MonitoringPointInfo = { + utilization_pct: 99, + over_threshold_since: "2024-01-01T00:00:00Z", + continuous_threshold_pct: 80, + }; + const result = getCircuitStateClasses(baseCircuit, info, false, true); + expect(result).toContain("circuit-off"); + expect(result).toContain("circuit-producer"); + expect(result).toContain("circuit-alert"); + expect(result).toContain("circuit-custom-monitoring"); + }); +}); +``` + +- [ ] **Step 2: Run the test to verify it fails** + +Run: `cd /Users/bflood/projects/HA/cards/span-card && npx vitest run tests/circuit-state.test.ts` + +Expected: FAIL with "Cannot find module '../src/core/circuit-state.js'". + +- [ ] **Step 3: Implement the helper** + +Create `src/core/circuit-state.ts`: + +```ts +import { hasCustomOverrides, isAlertActive } from "./monitoring-status.js"; +import type { Circuit, MonitoringPointInfo } from "../types.js"; + +/** + * Build the set of state-visualization classes that apply to a circuit's + * rendered slot. Shared by the breaker grid and the list view's + * chart-only expanded slot so both render the same border/background + * signaling. + */ +export function getCircuitStateClasses(_circuit: Circuit, monitoringInfo: MonitoringPointInfo | null, isOn: boolean, isProducer: boolean): string { + const classes: string[] = []; + if (!isOn) classes.push("circuit-off"); + if (isProducer) classes.push("circuit-producer"); + if (isAlertActive(monitoringInfo)) classes.push("circuit-alert"); + if (hasCustomOverrides(monitoringInfo)) classes.push("circuit-custom-monitoring"); + return classes.join(" "); +} +``` + +Note: `_circuit` is retained in the signature so future extensions (e.g. device-type specific classes) don't require a breaking change. The underscore prefix +tells ESLint it's intentionally unused. + +- [ ] **Step 4: Run the test to verify it passes** + +Run: `cd /Users/bflood/projects/HA/cards/span-card && npx vitest run tests/circuit-state.test.ts` + +Expected: 7 passing tests. + +- [ ] **Step 5: Typecheck** + +Run: `cd /Users/bflood/projects/HA/cards/span-card && npm run typecheck` + +Expected: no TypeScript errors. + +- [ ] **Step 6: Commit** + +```bash +cd /Users/bflood/projects/HA/cards/span-card +git add src/core/circuit-state.ts tests/circuit-state.test.ts +git commit -m "feat(core): extract shared getCircuitStateClasses helper" +``` + +--- + +## Task 2: Adopt `getCircuitStateClasses` in `renderCircuitSlot` + +Replace the inline class computation in `renderCircuitSlot` with a call to the shared helper, so the grid and list stay in lockstep. + +**Files:** + +- Modify: `src/core/grid-renderer.ts` + +- [ ] **Step 1: Read the current state-class logic** + +Open `src/core/grid-renderer.ts`. Lines 193-195 currently contain: + +```ts +const alertActive = isAlertActive(monitoringInfo); +const alertClass = alertActive ? "circuit-alert" : ""; +const customClass = hasOverridesFlag ? "circuit-custom-monitoring" : ""; +``` + +And line 202 uses them: + +```ts +
` line with: + +```ts +const stateClasses = getCircuitStateClasses(circuit, monitoringInfo, isOn, isProducer); +``` + +(add this line after the existing `const customClass` removal, before the template returns). Then change the opening div of the return template from: + +```ts +
{ + it("produces a list-expanded-content wrapper with the circuit uuid", () => { + const html = buildExpandedChartHTML("uuid-123", onCircuit, mockHass, mockConfig, null); + expect(html).toContain('class="list-expanded-content"'); + expect(html).toContain('data-expanded-uuid="uuid-123"'); + }); + + it("wraps a circuit-slot that carries the chart-only marker class and data-uuid", () => { + const html = buildExpandedChartHTML("uuid-123", onCircuit, mockHass, mockConfig, null); + expect(html).toContain("circuit-slot"); + expect(html).toContain("circuit-chart-only"); + expect(html).toContain('data-uuid="uuid-123"'); + }); + + it("contains exactly one chart-container div", () => { + const html = buildExpandedChartHTML("uuid-123", onCircuit, mockHass, mockConfig, null); + const matches = html.match(/class="chart-container"/g); + expect(matches?.length).toBe(1); + }); + + it("does NOT contain circuit-header or circuit-status duplicated content", () => { + const html = buildExpandedChartHTML("uuid-123", onCircuit, mockHass, mockConfig, null); + expect(html).not.toContain("circuit-header"); + expect(html).not.toContain("circuit-status"); + expect(html).not.toContain("toggle-pill"); + expect(html).not.toContain("breaker-badge"); + expect(html).not.toContain("power-value"); + }); + + it("applies circuit-off class when circuit is off", () => { + const off: Circuit = { ...onCircuit, relay_state: "OPEN", entities: { switch: undefined, power: "sensor.circuit_a_power" } }; + const html = buildExpandedChartHTML("uuid-123", off, mockHass, mockConfig, null); + expect(html).toContain("circuit-off"); + }); + + it("omits circuit-off class when circuit is on", () => { + const html = buildExpandedChartHTML("uuid-123", onCircuit, mockHass, mockConfig, null); + expect(html).not.toContain("circuit-off"); + }); + + it("escapes unsafe uuids", () => { + const html = buildExpandedChartHTML('">', onCircuit, mockHass, mockConfig, null); + expect(html).not.toContain("', onCircuit, mockHass, mockConfig, null); + expect(html).not.toContain("', onCircuit, mockHass, mockConfig, null); - expect(html).not.toContain("', onCircuit, mockHass, mockConfig, null); + expect(html).not.toContain("', onCircuit, mockHass, mockConfig, null); - expect(html).not.toContain("