// Simplified Discovery Integration // Updated for simplified signal names + tags architecture class SimplifiedProtocolDiscovery { constructor() { this.currentScanId = 'simplified-scan-123'; this.isScanning = false; } init() { this.bindDiscoveryEvents(); } bindDiscoveryEvents() { // Discovery scan button const startScanBtn = document.getElementById('start-discovery-scan'); if (startScanBtn) { startScanBtn.addEventListener('click', () => { this.startDiscoveryScan(); }); } // Auto-fill signal form from discovery document.addEventListener('click', (e) => { if (e.target.classList.contains('use-discovered-endpoint')) { this.useDiscoveredEndpoint(e.target.dataset.endpointId); } }); } async useDiscoveredEndpoint(endpointId) { console.log('Using discovered endpoint:', endpointId); // Mock endpoint data (in real implementation, this would come from discovery service) const endpoints = { 'device_001': { device_id: 'device_001', protocol_type: 'modbus_tcp', device_name: 'Water Pump Controller', address: '192.168.1.100', port: 502, data_point: 'Speed', protocol_address: '40001' }, 'device_002': { device_id: 'device_002', protocol_type: 'opcua', device_name: 'Temperature Sensor', address: '192.168.1.101', port: 4840, data_point: 'Temperature', protocol_address: 'ns=2;s=Temperature' }, 'device_003': { device_id: 'device_003', protocol_type: 'modbus_tcp', device_name: 'Pressure Transmitter', address: '192.168.1.102', port: 502, data_point: 'Pressure', protocol_address: '30001' } }; const endpoint = endpoints[endpointId]; if (!endpoint) { this.showNotification(`Endpoint ${endpointId} not found`, 'error'); return; } // Convert to simplified signal format const signalData = this.convertEndpointToSignal(endpoint); // Auto-populate the signal form this.autoPopulateSignalForm(signalData); this.showNotification(`Endpoint ${endpoint.device_name} selected for signal creation`, 'success'); } convertEndpointToSignal(endpoint) { // Generate human-readable signal name const signalName = `${endpoint.device_name} ${endpoint.data_point}`; // Generate meaningful tags const tags = [ `device:${endpoint.device_name.toLowerCase().replace(/[^a-z0-9]/g, '_')}`, `protocol:${endpoint.protocol_type}`, `data_point:${endpoint.data_point.toLowerCase().replace(/[^a-z0-9]/g, '_')}`, 'discovered:true' ]; // Add device-specific tags if (endpoint.device_name.toLowerCase().includes('pump')) { tags.push('equipment:pump'); } if (endpoint.device_name.toLowerCase().includes('sensor')) { tags.push('equipment:sensor'); } if (endpoint.device_name.toLowerCase().includes('controller')) { tags.push('equipment:controller'); } // Add protocol-specific tags if (endpoint.protocol_type === 'modbus_tcp') { tags.push('interface:modbus'); } else if (endpoint.protocol_type === 'opcua') { tags.push('interface:opcua'); } // Generate database source const dbSource = `measurements.${endpoint.device_name.toLowerCase().replace(/[^a-z0-9]/g, '_')}_${endpoint.data_point.toLowerCase().replace(/[^a-z0-9]/g, '_')}`; return { signal_name: signalName, tags: tags, protocol_type: endpoint.protocol_type, protocol_address: endpoint.protocol_address, db_source: dbSource }; } autoPopulateSignalForm(signalData) { console.log('Auto-populating signal form with:', signalData); // Use the simplified protocol mapping function if (typeof window.autoPopulateSignalForm === 'function') { window.autoPopulateSignalForm(signalData); } else { console.error('Simplified protocol mapping functions not loaded'); this.showNotification('Protocol mapping system not available', 'error'); } } // Start discovery scan async startDiscoveryScan() { console.log('Starting discovery scan...'); // Update UI const startBtn = document.getElementById('start-discovery-scan'); const stopBtn = document.getElementById('stop-discovery-scan'); const statusDiv = document.getElementById('discovery-status'); if (startBtn) startBtn.disabled = true; if (stopBtn) stopBtn.disabled = false; if (statusDiv) { statusDiv.innerHTML = '
Discovery scan in progress...
'; } try { // Run discovery const results = await this.discoverAndSuggestSignals(); // Update status if (statusDiv) { statusDiv.innerHTML = `
Discovery complete. Found ${results.length} devices.
`; } this.showNotification(`Discovery complete. Found ${results.length} devices.`, 'success'); } catch (error) { console.error('Discovery scan failed:', error); if (statusDiv) { statusDiv.innerHTML = '
Discovery scan failed
'; } this.showNotification('Discovery scan failed', 'error'); } finally { // Reset UI if (startBtn) startBtn.disabled = false; if (stopBtn) stopBtn.disabled = true; } } // Advanced discovery features async discoverAndSuggestSignals(networkRange = '192.168.1.0/24') { console.log(`Starting discovery scan on ${networkRange}`); this.isScanning = true; try { // Mock discovery results const discoveredEndpoints = await this.mockDiscoveryScan(networkRange); // Convert to suggested signals const suggestedSignals = discoveredEndpoints.map(endpoint => this.convertEndpointToSignal(endpoint) ); this.displayDiscoveryResults(suggestedSignals); this.isScanning = false; return suggestedSignals; } catch (error) { console.error('Discovery scan failed:', error); this.showNotification('Discovery scan failed', 'error'); this.isScanning = false; return []; } } async mockDiscoveryScan(networkRange) { // Simulate network discovery delay await new Promise(resolve => setTimeout(resolve, 2000)); // Return mock discovered endpoints return [ { device_id: 'discovered_001', protocol_type: 'modbus_tcp', device_name: 'Booster Pump', address: '192.168.1.110', port: 502, data_point: 'Flow Rate', protocol_address: '30002' }, { device_id: 'discovered_002', protocol_type: 'modbus_tcp', device_name: 'Level Sensor', address: '192.168.1.111', port: 502, data_point: 'Tank Level', protocol_address: '30003' }, { device_id: 'discovered_003', protocol_type: 'opcua', device_name: 'PLC Controller', address: '192.168.1.112', port: 4840, data_point: 'System Status', protocol_address: 'ns=2;s=SystemStatus' } ]; } displayDiscoveryResults(suggestedSignals) { console.log('Displaying discovery results:', suggestedSignals); const resultsContainer = document.getElementById('discovery-results'); if (!resultsContainer) { console.error('Discovery results container not found!'); this.showNotification('Discovery results container not found', 'error'); return; } resultsContainer.innerHTML = '

Discovery Results

'; suggestedSignals.forEach((signal, index) => { const signalCard = document.createElement('div'); signalCard.className = 'discovery-result-card'; signalCard.innerHTML = `
${signal.signal_name}
${signal.tags.map(tag => `${tag}`).join('')}
Protocol: ${signal.protocol_type} Address: ${signal.protocol_address}
`; resultsContainer.appendChild(signalCard); }); // Add event listeners for use buttons resultsContainer.addEventListener('click', (e) => { if (e.target.classList.contains('use-signal-btn')) { const signalIndex = parseInt(e.target.dataset.signalIndex); const signal = suggestedSignals[signalIndex]; this.autoPopulateSignalForm(signal); } }); // Add "Apply All" button const applyAllButton = document.createElement('button'); applyAllButton.className = 'apply-all-btn'; applyAllButton.textContent = 'Apply All as Protocol Signals'; applyAllButton.style.marginTop = '15px'; applyAllButton.style.padding = '10px 20px'; applyAllButton.style.background = '#28a745'; applyAllButton.style.color = 'white'; applyAllButton.style.border = 'none'; applyAllButton.style.borderRadius = '4px'; applyAllButton.style.cursor = 'pointer'; applyAllButton.style.fontWeight = 'bold'; applyAllButton.onclick = () => { this.applyAllAsProtocolSignals(suggestedSignals); }; resultsContainer.appendChild(applyAllButton); } // Apply all discovered signals as protocol signals async applyAllAsProtocolSignals(signals) { console.log('Applying all discovered signals as protocol signals:', signals); let successCount = 0; let errorCount = 0; for (const signal of signals) { try { const response = await fetch('/api/v1/dashboard/protocol-signals', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(signal) }); const data = await response.json(); if (data.success) { successCount++; console.log(`✓ Created signal: ${signal.signal_name}`); } else { errorCount++; console.error(`✗ Failed to create signal: ${signal.signal_name}`, data.detail); } } catch (error) { errorCount++; console.error(`✗ Error creating signal: ${signal.signal_name}`, error); } } // Show results const message = `Created ${successCount} signals successfully. ${errorCount > 0 ? `${errorCount} failed.` : ''}`; this.showNotification(message, errorCount > 0 ? 'warning' : 'success'); // Refresh the protocol signals display if (typeof window.loadAllSignals === 'function') { window.loadAllSignals(); } } // Tag-based signal search async searchSignalsByTags(tags) { try { const params = new URLSearchParams(); tags.forEach(tag => params.append('tags', tag)); const response = await fetch(`/api/v1/dashboard/protocol-signals?${params}`); const data = await response.json(); if (data.success) { return data.signals; } else { console.error('Failed to search signals by tags:', data.detail); return []; } } catch (error) { console.error('Error searching signals by tags:', error); return []; } } // Signal name suggestions based on device type generateSignalNameSuggestions(deviceName, dataPoint) { const baseName = `${deviceName} ${dataPoint}`; const suggestions = [ baseName, `${dataPoint} of ${deviceName}`, `${deviceName} ${dataPoint} Reading`, `${dataPoint} Measurement - ${deviceName}` ]; // Add context-specific suggestions if (dataPoint.toLowerCase().includes('speed')) { suggestions.push(`${deviceName} Motor Speed`); suggestions.push(`${deviceName} RPM`); } if (dataPoint.toLowerCase().includes('temperature')) { suggestions.push(`${deviceName} Temperature`); suggestions.push(`Temperature at ${deviceName}`); } if (dataPoint.toLowerCase().includes('pressure')) { suggestions.push(`${deviceName} Pressure`); suggestions.push(`Pressure Reading - ${deviceName}`); } return suggestions; } // Tag suggestions based on device and protocol generateTagSuggestions(deviceName, protocolType, dataPoint) { const suggestions = new Set(); // Device type tags if (deviceName.toLowerCase().includes('pump')) { suggestions.add('equipment:pump'); suggestions.add('fluid:water'); } if (deviceName.toLowerCase().includes('sensor')) { suggestions.add('equipment:sensor'); suggestions.add('type:measurement'); } if (deviceName.toLowerCase().includes('controller')) { suggestions.add('equipment:controller'); suggestions.add('type:control'); } // Protocol tags suggestions.add(`protocol:${protocolType}`); if (protocolType === 'modbus_tcp' || protocolType === 'modbus_rtu') { suggestions.add('interface:modbus'); } else if (protocolType === 'opcua') { suggestions.add('interface:opcua'); } // Data point tags suggestions.add(`data_point:${dataPoint.toLowerCase().replace(/[^a-z0-9]/g, '_')}`); if (dataPoint.toLowerCase().includes('speed')) { suggestions.add('unit:rpm'); suggestions.add('type:setpoint'); } if (dataPoint.toLowerCase().includes('temperature')) { suggestions.add('unit:celsius'); suggestions.add('type:measurement'); } if (dataPoint.toLowerCase().includes('pressure')) { suggestions.add('unit:psi'); suggestions.add('type:measurement'); } if (dataPoint.toLowerCase().includes('status')) { suggestions.add('type:status'); suggestions.add('format:boolean'); } // Discovery tag suggestions.add('discovered:true'); return Array.from(suggestions); } showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `discovery-notification ${type}`; notification.textContent = message; document.body.appendChild(notification); // Auto-remove after 5 seconds setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 5000); } } // Global instance const simplifiedDiscovery = new SimplifiedProtocolDiscovery(); // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', function() { simplifiedDiscovery.init(); });