class PfSenseCommandCenterCard extends HTMLElement { setConfig(config) { this.config = config; // Track open/closed states for all four master accordion windows this.sectionsOpen = this.sectionsOpen || { control: false, interfaces: false, gateways: false, services: false }; this.logHistory = this.logHistory || [ "[SUCCESS] pfSense Command Engine synchronized successfully.", "[INFO] All system monitoring modules active." ]; } set hass(hass) { this._hass = hass; // --- UNIVERSAL AUTO-DISCOVERY ENGINE --- const allEntityIds = Object.keys(hass.states); // Intercept all pfSense metrics and core third-party infrastructure daemons const pfEntities = allEntityIds.filter(id => id.startsWith('sensor.pfsense_') || id.startsWith('switch.pfsense_') || id.includes('_service_') ); // Resolve structural system variables cleanly const wanIpId = pfEntities.find(id => id.includes('wan_ip_address')) || ''; const dnsblId = pfEntities.find(id => id.includes('dnsbl_blocks')) || ''; const ipBlocksId = pfEntities.find(id => id.includes('ip_blocks')) || ''; const memId = pfEntities.find(id => id.includes('memory_used_percentage')) || ''; const dhcpId = pfEntities.find(id => id.includes('dhcp_leases_online')) || ''; const cpuId = pfEntities.find(id => id.includes('cpu_usage') || id.includes('cpu_used_percent')) || ''; const bootId = pfEntities.find(id => id.includes('system_boottime')) || ''; const wanIp = wanIpId && hass.states[wanIpId] ? hass.states[wanIpId].state : 'Disconnected'; const dnsbl = dnsblId && hass.states[dnsblId] ? hass.states[dnsblId].state : '0'; const ipBlocks = ipBlocksId && hass.states[ipBlocksId] ? hass.states[ipBlocksId].state : '0'; const memUsed = memId && hass.states[memId] ? hass.states[memId].state : '0'; const dhcpOnline = dhcpId && hass.states[dhcpId] ? hass.states[dhcpId].state : '0'; const cpuUsed = cpuId && hass.states[cpuId] ? hass.states[cpuId].state : '0'; let bootTimeStr = 'Unknown'; if (bootId && hass.states[bootId]) { const rawBoot = hass.states[bootId].state; bootTimeStr = rawBoot.includes('T') ? rawBoot.replace('T', ' ').substring(0, 16) : rawBoot; } // Process and sort nested items dynamically const interfaces = {}; const gateways = {}; const services = []; pfEntities.forEach(id => { const stateObj = hass.states[id]; if (!stateObj) return; if (id.includes('_interface_') && id.endsWith('_status')) { const match = id.match(/_interface_(.*?)_status/); if (match) { const ifName = match[1]; interfaces[ifName] = { id: id, status: stateObj.state, props: {} }; pfEntities.filter(p => p.includes(`_interface_${ifName}_`)).forEach(pId => { const propName = pId.split(`_interface_${ifName}_`)[1]; interfaces[ifName].props[propName] = hass.states[pId].state; }); } } if (id.includes('_gateway_') && id.endsWith('_status')) { const match = id.match(/_gateway_(.*?)_status/); if (match) { const gwName = match[1]; gateways[gwName] = { id: id, status: stateObj.state, props: {} }; pfEntities.filter(p => p.includes(`_gateway_${gwName}_`)).forEach(pId => { const propName = pId.split(`_gateway_${gwName}_`)[1]; gateways[gwName].props[propName] = hass.states[pId].state; }); } } if (id.startsWith('switch.') && (id.includes('_service_') || id.includes('pfsense_service_'))) { services.push({ id: id, state: stateObj.state, friendlyName: stateObj.attributes.friendly_name || id }); } }); // Draw the main card framework once to guarantee DOM stability if (!this.content) { this.innerHTML = `

pfSense Command Center

Global Real-Time Telemetry Engine

0 BLOCKS SINKHOLED

Memory

${memUsed}%
RAM Load

CPU Load

${cpuUsed}%
Processor

DHCP Leases

${dhcpOnline}
Active Clients

External IP

${wanIp}
Border WAN
PFsense Control
BOOTTIME MARKER: ${bootTimeStr}
Physical & Virtual Interfaces
Dynamic Gateway Routing Topology
Daemon Services & Tunnel Protection

Dynamic Policy Routing & Alias Management

PFSENSE COMPONENT LOG STREAM
LIVE FEED
`; this.content = this.querySelector('#console-stream'); // Hook core routine executors safely this.querySelector('#btn-add').addEventListener('click', () => this.fireAliasService('add')); this.querySelector('#btn-rem').addEventListener('click', () => this.fireAliasService('remove')); this.querySelector('#maint-flush').addEventListener('click', () => this.fireMaintenanceService('reset_state_table', 'FLUSH FIREWALL TABLES')); this.querySelector('#maint-reboot').addEventListener('click', () => this.fireMaintenanceService('system_reboot', 'REBOOT APPLIANCE MACHINE')); this.querySelector('#maint-halt').addEventListener('click', () => this.fireMaintenanceService('system_halt', 'POWER DOWN AND HALT THE GATEWAY ENGINE')); // Bind all four accordion triggers to their layout drawers seamlessly ['control', 'interfaces', 'gateways', 'services'].forEach(key => { this.querySelector(`#sec-${key} .section-trigger`).addEventListener('click', () => { this.sectionsOpen[key] = !this.sectionsOpen[key]; this.querySelector(`#sec-${key}`).classList.toggle('open', this.sectionsOpen[key]); }); }); } // --- DIRECT HIGH-SPEED TELEMETRY SYNC LOOP --- this.querySelector('#deck-mem').innerText = `${memUsed}%`; this.querySelector('#deck-cpu').innerText = `${cpuUsed}%`; this.querySelector('#deck-dhcp').innerText = dhcpOnline; this.querySelector('#deck-wan').innerText = wanIp; this.querySelector('#maint-boottime').innerText = `BOOTTIME MARKER: ${bootTimeStr}`; // --- POPULATE AND RE-RENDER INTERFACES SUBGRID --- const ifContainer = this.querySelector('#interfaces-container'); if (ifContainer) { if (Object.keys(interfaces).length === 0) { ifContainer.innerHTML = `
No active interfaces tracked.
`; } else { ifContainer.innerHTML = Object.keys(interfaces).map(name => { const item = interfaces[name]; const cleanName = name.toUpperCase(); const speedIn = item.props['inbytes_kilobytes_per_second'] || '0'; const speedOut = item.props['outbytes_kilobytes_per_second'] || '0'; return `

Link ${cleanName}

Physical Port State Tracking

RX:${speedIn} KB/s
TX:${speedOut} KB/s
`; }).join(''); } } // --- POPULATE AND RE-RENDER GATEWAYS SUBGRID --- const gwContainer = this.querySelector('#gateways-container'); if (gwContainer) { if (Object.keys(gateways).length === 0) { gwContainer.innerHTML = `
No active gateways discovered.
`; } else { gwContainer.innerHTML = Object.keys(gateways).map(name => { const item = gateways[name]; const cleanName = name.replace('_status', '').toUpperCase(); const delay = item.props['delay'] || '0 ms'; const loss = item.props['loss'] || '0%'; return `

${cleanName}

Gateway Router Backhaul Link

RTT:${delay}
LOS:${loss}
`; }).join(''); } } // --- POPULATE AND RE-RENDER SWITCH CONTROL ENGINE DECK --- const srvContainer = this.querySelector('#services-container'); if (srvContainer) { if (services.length === 0) { srvContainer.innerHTML = `
No network switches found.
`; } else { srvContainer.innerHTML = services.map(srv => { const isActive = srv.state === 'on'; let label = srv.friendlyName.replace('pfSense ', '').replace('Service ', '').replace('status', '').replace('Status', '').trim(); return `
${label}

${srv.state}

`; }).join(''); // Wire service call bindings cleanly back to Home Assistant platform core this.querySelectorAll('.deck-switch-btn').forEach(btn => { btn.addEventListener('click', (e) => { const entId = e.currentTarget.getAttribute('data-id'); const currentState = e.currentTarget.querySelector('p').innerText; const targetService = currentState === 'on' ? 'turn_off' : 'turn_on'; const targetName = e.currentTarget.querySelector('h5').innerText; if (confirm(`CRITICAL INFRASTRUCTURE WARNING:\nAre you sure you want to change network routing state for: ${targetName}?`)) { this.addLogEntry(`[DAEMON] Modifying service path: ${targetName} -> ${targetService.toUpperCase()}`); this._hass.callService('switch', targetService, { entity_id: entId }); } }); }); } } const totalBlocks = parseInt(dnsbl) + parseInt(ipBlocks); this.querySelector('#block-counter').innerText = `${totalBlocks} BLOCKS SINKHOLED`; this.renderConsole(); } addLogEntry(message) { const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19); this.logHistory.unshift(`[${timestamp}] ${message}`); if (this.logHistory.length > 15) this.logHistory.pop(); this.renderConsole(); } renderConsole() { if (!this.content) return; this.content.innerHTML = this.logHistory.map(line => `
${line}
`).join(''); } async fireMaintenanceService(serviceName, warningText) { const allEntityIds = Object.keys(this._hass.states); const fallbackEntity = allEntityIds.find(id => id.startsWith('sensor.pfsense_') && id.includes('wan_ip_address')) || ''; if (!confirm(`CRITICAL APPLIANCE ALERT:\nAre you sure you want to execute command:\n-> [ ${warningText} ]?\n\nThis will instantly disrupt local network traffic.`)) { return; } this.addLogEntry(`[MAINTENANCE] Firing system executive instruction: ${serviceName.toUpperCase()}`); try { await this._hass.callService('pfsense', serviceName, { entity_id: fallbackEntity }); this.addLogEntry(`[SUCCESS] Instruction handled by pfSense API Client.`); } catch(err) { this.addLogEntry(`[ERROR] Maintenance execution call dropped: ${err.message}`); } } async fireAliasService(actionType) { const aliasName = this.querySelector('#alias-name').value.trim(); const targetIp = this.querySelector('#target-ip').value.trim(); const allEntityIds = Object.keys(this._hass.states); const fallbackEntity = allEntityIds.find(id => id.startsWith('sensor.pfsense_') && id.includes('wan_ip_address')) || ''; if (!aliasName || !targetIp) { this.addLogEntry(`[WARNING] Input validation failed. Check parameter syntax variables.`); return; } if (!confirm(`SECURITY ALERT: Alter alias tracking configuration row?\nTable: ${aliasName}\nTarget address: ${targetIp}\nOperation: ${actionType.toUpperCase()}`)) { return; } this.addLogEntry(`[PENDING] Modifying table '${aliasName}': ${actionType.toUpperCase()} -> ${targetIp}`); try { await this._hass.callService('pfsense', 'update_alias', { entity_id: fallbackEntity, alias_name: aliasName, address: targetIp, action: actionType, kill_states: true }); this.addLogEntry(`[SUCCESS] Table written. Active states matching ${targetIp} terminated.`); } catch (err) { this.addLogEntry(`[ERROR] API transmission error: ${err.message}`); } } getCardSize() { return 8; } } customElements.define('pfsense-command-center-card', PfSenseCommandCenterCard);