328 lines
16 KiB
HTML
328 lines
16 KiB
HTML
|
|
<!DOCTYPE html>
|
||
|
|
<html>
|
||
|
|
<head>
|
||
|
|
<title>Protocol Discovery Test</title>
|
||
|
|
<style>
|
||
|
|
.modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); }
|
||
|
|
.modal-content { background-color: white; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 50%; }
|
||
|
|
.close { color: #aaa; float: right; font-size: 28px; font-weight: bold; cursor: pointer; }
|
||
|
|
.form-group { margin-bottom: 15px; }
|
||
|
|
label { display: block; margin-bottom: 5px; font-weight: bold; }
|
||
|
|
input, select { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
|
||
|
|
button { background: #007acc; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; margin: 5px; }
|
||
|
|
.alert { padding: 10px; border-radius: 4px; margin: 10px 0; }
|
||
|
|
.alert.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
||
|
|
.alert.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<h1>Protocol Discovery Test</h1>
|
||
|
|
|
||
|
|
<div style="border: 1px solid #ccc; padding: 20px; margin: 20px 0;">
|
||
|
|
<h2>Test Discovery "Use" Button</h2>
|
||
|
|
<button onclick="testDiscovery()">Test Discovery Use Button</button>
|
||
|
|
<button onclick="showAddMappingModal()">Open Modal Manually</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Add/Edit Mapping Modal -->
|
||
|
|
<div id="mapping-modal" class="modal">
|
||
|
|
<div class="modal-content">
|
||
|
|
<span class="close" onclick="closeMappingModal()">×</span>
|
||
|
|
<h3 id="modal-title">Add Protocol Mapping</h3>
|
||
|
|
<form id="mapping-form">
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="mapping_id">Mapping ID:</label>
|
||
|
|
<input type="text" id="mapping_id" name="mapping_id" required>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="protocol_type">Protocol Type:</label>
|
||
|
|
<select id="protocol_type" name="protocol_type" required onchange="updateProtocolFields()">
|
||
|
|
<option value="">Select Protocol</option>
|
||
|
|
<option value="modbus_tcp">Modbus TCP</option>
|
||
|
|
<option value="opcua">OPC UA</option>
|
||
|
|
<option value="modbus_rtu">Modbus RTU</option>
|
||
|
|
<option value="rest_api">REST API</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="station_id">Station:</label>
|
||
|
|
<select id="station_id" name="station_id" required>
|
||
|
|
<option value="">Select Station</option>
|
||
|
|
<option value="station_main">Main Pump Station</option>
|
||
|
|
<option value="station_backup">Backup Pump Station</option>
|
||
|
|
<option value="station_control">Control Station</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="equipment_id">Equipment:</label>
|
||
|
|
<select id="equipment_id" name="equipment_id" required>
|
||
|
|
<option value="">Select Equipment</option>
|
||
|
|
<option value="pump_primary">Primary Pump</option>
|
||
|
|
<option value="pump_backup">Backup Pump</option>
|
||
|
|
<option value="sensor_pressure">Pressure Sensor</option>
|
||
|
|
<option value="sensor_flow">Flow Meter</option>
|
||
|
|
<option value="valve_control">Control Valve</option>
|
||
|
|
<option value="controller_plc">PLC Controller</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="data_type_id">Data Type:</label>
|
||
|
|
<select id="data_type_id" name="data_type_id" required>
|
||
|
|
<option value="">Select Data Type</option>
|
||
|
|
<option value="speed_pump">Pump Speed</option>
|
||
|
|
<option value="pressure_water">Water Pressure</option>
|
||
|
|
<option value="status_pump">Pump Status</option>
|
||
|
|
<option value="flow_rate">Flow Rate</option>
|
||
|
|
<option value="position_valve">Valve Position</option>
|
||
|
|
<option value="emergency_stop">Emergency Stop</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="protocol_address">Protocol Address:</label>
|
||
|
|
<input type="text" id="protocol_address" name="protocol_address" required>
|
||
|
|
<small id="protocol_address_help" style="color: #666;"></small>
|
||
|
|
</div>
|
||
|
|
<div class="form-group">
|
||
|
|
<label for="db_source">Database Source:</label>
|
||
|
|
<input type="text" id="db_source" name="db_source" required placeholder="table.column">
|
||
|
|
</div>
|
||
|
|
<div class="action-buttons">
|
||
|
|
<button type="button" onclick="validateMapping()">Validate</button>
|
||
|
|
<button type="submit" style="background: #28a745;">Save Mapping</button>
|
||
|
|
<button type="button" onclick="closeMappingModal()" style="background: #dc3545;">Cancel</button>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Notifications -->
|
||
|
|
<div id="discovery-notifications"></div>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
// Modal functions
|
||
|
|
function showAddMappingModal() {
|
||
|
|
console.log('showAddMappingModal called');
|
||
|
|
document.getElementById('modal-title').textContent = 'Add Protocol Mapping';
|
||
|
|
document.getElementById('mapping-form').reset();
|
||
|
|
document.getElementById('protocol_address_help').textContent = '';
|
||
|
|
document.getElementById('mapping-modal').style.display = 'block';
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeMappingModal() {
|
||
|
|
document.getElementById('mapping-modal').style.display = 'none';
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateProtocolFields() {
|
||
|
|
const protocolType = document.getElementById('protocol_type').value;
|
||
|
|
const helpText = document.getElementById('protocol_address_help');
|
||
|
|
|
||
|
|
switch (protocolType) {
|
||
|
|
case 'modbus_tcp':
|
||
|
|
helpText.textContent = 'Modbus address format: 40001 (holding register), 30001 (input register), 10001 (coil), 00001 (discrete input)';
|
||
|
|
break;
|
||
|
|
case 'opcua':
|
||
|
|
helpText.textContent = 'OPC UA NodeId format: ns=2;s=MyVariable or ns=2;i=1234';
|
||
|
|
break;
|
||
|
|
case 'modbus_rtu':
|
||
|
|
helpText.textContent = 'Modbus RTU address format: 40001 (holding register), 30001 (input register), 10001 (coil), 00001 (discrete input)';
|
||
|
|
break;
|
||
|
|
case 'rest_api':
|
||
|
|
helpText.textContent = 'REST API endpoint format: /api/v1/data/endpoint';
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
helpText.textContent = '';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function validateMapping() {
|
||
|
|
alert('Mapping validation would be performed here');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test function
|
||
|
|
function testDiscovery() {
|
||
|
|
console.log('Testing discovery functionality...');
|
||
|
|
|
||
|
|
// Simulate a discovered endpoint
|
||
|
|
const endpoint = {
|
||
|
|
device_id: 'device_001',
|
||
|
|
protocol_type: 'modbus_tcp',
|
||
|
|
device_name: 'Water Pump Controller',
|
||
|
|
address: '192.168.1.100',
|
||
|
|
port: 502
|
||
|
|
};
|
||
|
|
|
||
|
|
// Create a new protocol mapping ID
|
||
|
|
const mappingId = `${endpoint.device_id}_${endpoint.protocol_type}`;
|
||
|
|
|
||
|
|
// Get default metadata IDs
|
||
|
|
const defaultStationId = 'station_main';
|
||
|
|
const defaultEquipmentId = 'pump_primary';
|
||
|
|
const defaultDataTypeId = 'speed_pump';
|
||
|
|
|
||
|
|
// Set form values
|
||
|
|
const formData = {
|
||
|
|
mapping_id: mappingId,
|
||
|
|
protocol_type: endpoint.protocol_type === 'opc_ua' ? 'opcua' : endpoint.protocol_type,
|
||
|
|
protocol_address: '40001',
|
||
|
|
device_name: endpoint.device_name || endpoint.device_id,
|
||
|
|
device_address: endpoint.address,
|
||
|
|
device_port: endpoint.port || '',
|
||
|
|
station_id: defaultStationId,
|
||
|
|
equipment_id: defaultEquipmentId,
|
||
|
|
data_type_id: defaultDataTypeId
|
||
|
|
};
|
||
|
|
|
||
|
|
console.log('Form data created:', formData);
|
||
|
|
|
||
|
|
// Auto-populate the protocol mapping form
|
||
|
|
autoPopulateProtocolForm(formData);
|
||
|
|
}
|
||
|
|
|
||
|
|
function autoPopulateProtocolForm(formData) {
|
||
|
|
console.log('Auto-populating protocol form with:', formData);
|
||
|
|
|
||
|
|
// First, open the "Add New Mapping" modal
|
||
|
|
showAddMappingModal();
|
||
|
|
|
||
|
|
// Wait for modal to be fully loaded and visible
|
||
|
|
const waitForModal = setInterval(() => {
|
||
|
|
const modal = document.getElementById('mapping-modal');
|
||
|
|
const isModalVisible = modal && modal.style.display !== 'none';
|
||
|
|
|
||
|
|
if (isModalVisible) {
|
||
|
|
clearInterval(waitForModal);
|
||
|
|
populateModalFields(formData);
|
||
|
|
}
|
||
|
|
}, 50);
|
||
|
|
|
||
|
|
// Timeout after 2 seconds
|
||
|
|
setTimeout(() => {
|
||
|
|
clearInterval(waitForModal);
|
||
|
|
const modal = document.getElementById('mapping-modal');
|
||
|
|
if (modal && modal.style.display !== 'none') {
|
||
|
|
populateModalFields(formData);
|
||
|
|
} else {
|
||
|
|
console.error('Modal did not open within timeout period');
|
||
|
|
showNotification('Could not open protocol mapping form. Please try opening it manually.', 'error');
|
||
|
|
}
|
||
|
|
}, 2000);
|
||
|
|
}
|
||
|
|
|
||
|
|
function populateModalFields(formData) {
|
||
|
|
console.log('Populating modal fields with:', formData);
|
||
|
|
|
||
|
|
// Find and populate form fields in the modal
|
||
|
|
const mappingIdField = document.getElementById('mapping_id');
|
||
|
|
const protocolTypeField = document.getElementById('protocol_type');
|
||
|
|
const protocolAddressField = document.getElementById('protocol_address');
|
||
|
|
const stationIdField = document.getElementById('station_id');
|
||
|
|
const equipmentIdField = document.getElementById('equipment_id');
|
||
|
|
const dataTypeIdField = document.getElementById('data_type_id');
|
||
|
|
const dbSourceField = document.getElementById('db_source');
|
||
|
|
|
||
|
|
console.log('Found fields:', {
|
||
|
|
mappingIdField: !!mappingIdField,
|
||
|
|
protocolTypeField: !!protocolTypeField,
|
||
|
|
protocolAddressField: !!protocolAddressField,
|
||
|
|
stationIdField: !!stationIdField,
|
||
|
|
equipmentIdField: !!equipmentIdField,
|
||
|
|
dataTypeIdField: !!dataTypeIdField,
|
||
|
|
dbSourceField: !!dbSourceField
|
||
|
|
});
|
||
|
|
|
||
|
|
// Populate mapping ID
|
||
|
|
if (mappingIdField) {
|
||
|
|
mappingIdField.value = formData.mapping_id;
|
||
|
|
console.log('✓ Set mapping_id to:', formData.mapping_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Populate protocol type
|
||
|
|
if (protocolTypeField) {
|
||
|
|
protocolTypeField.value = formData.protocol_type;
|
||
|
|
console.log('✓ Set protocol_type to:', formData.protocol_type);
|
||
|
|
// Trigger protocol field updates
|
||
|
|
protocolTypeField.dispatchEvent(new Event('change'));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Populate protocol address
|
||
|
|
if (protocolAddressField) {
|
||
|
|
protocolAddressField.value = formData.protocol_address;
|
||
|
|
console.log('✓ Set protocol_address to:', formData.protocol_address);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set station, equipment, and data type
|
||
|
|
if (stationIdField) {
|
||
|
|
if (isValidStationId(formData.station_id)) {
|
||
|
|
stationIdField.value = formData.station_id;
|
||
|
|
console.log('✓ Set station_id to:', formData.station_id);
|
||
|
|
// Trigger equipment dropdown update
|
||
|
|
stationIdField.dispatchEvent(new Event('change'));
|
||
|
|
|
||
|
|
// Wait for equipment to be loaded
|
||
|
|
setTimeout(() => {
|
||
|
|
if (equipmentIdField && isValidEquipmentId(formData.equipment_id)) {
|
||
|
|
equipmentIdField.value = formData.equipment_id;
|
||
|
|
console.log('✓ Set equipment_id to:', formData.equipment_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (dataTypeIdField && isValidDataTypeId(formData.data_type_id)) {
|
||
|
|
dataTypeIdField.value = formData.data_type_id;
|
||
|
|
console.log('✓ Set data_type_id to:', formData.data_type_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Set default database source
|
||
|
|
if (dbSourceField && !dbSourceField.value) {
|
||
|
|
dbSourceField.value = 'measurements.' + formData.device_name.toLowerCase().replace(/[^a-z0-9]/g, '_');
|
||
|
|
console.log('✓ Set db_source to:', dbSourceField.value);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Show success message
|
||
|
|
showNotification(`Protocol form populated with ${formData.device_name}. Please review and complete any missing information.`, 'success');
|
||
|
|
}, 100);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function isValidStationId(stationId) {
|
||
|
|
const stationSelect = document.getElementById('station_id');
|
||
|
|
if (!stationSelect) return false;
|
||
|
|
return Array.from(stationSelect.options).some(option => option.value === stationId);
|
||
|
|
}
|
||
|
|
|
||
|
|
function isValidEquipmentId(equipmentId) {
|
||
|
|
const equipmentSelect = document.getElementById('equipment_id');
|
||
|
|
if (!equipmentSelect) return false;
|
||
|
|
return Array.from(equipmentSelect.options).some(option => option.value === equipmentId);
|
||
|
|
}
|
||
|
|
|
||
|
|
function isValidDataTypeId(dataTypeId) {
|
||
|
|
const dataTypeSelect = document.getElementById('data_type_id');
|
||
|
|
if (!dataTypeSelect) return false;
|
||
|
|
return Array.from(dataTypeSelect.options).some(option => option.value === dataTypeId);
|
||
|
|
}
|
||
|
|
|
||
|
|
function showNotification(message, type = 'info') {
|
||
|
|
const alertClass = {
|
||
|
|
'success': 'alert-success',
|
||
|
|
'error': 'alert-danger',
|
||
|
|
'warning': 'alert-warning',
|
||
|
|
'info': 'alert-info'
|
||
|
|
}[type] || 'alert-info';
|
||
|
|
|
||
|
|
const notification = document.createElement('div');
|
||
|
|
notification.className = `alert ${alertClass}`;
|
||
|
|
notification.innerHTML = message;
|
||
|
|
|
||
|
|
const container = document.getElementById('discovery-notifications');
|
||
|
|
container.appendChild(notification);
|
||
|
|
|
||
|
|
// Auto-remove after 5 seconds
|
||
|
|
setTimeout(() => {
|
||
|
|
if (notification.parentNode) {
|
||
|
|
notification.remove();
|
||
|
|
}
|
||
|
|
}, 5000);
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|