// 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);
// Ensure protocol mapping tab is active
if (typeof showTab === 'function') {
showTab('protocol-mapping');
}
// Use the simplified protocol mapping function
if (typeof window.autoPopulateSignalForm === 'function') {
// Add a small delay to ensure the tab is loaded
setTimeout(() => {
window.autoPopulateSignalForm(signalData);
}, 100);
} 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();
});