feat: Implement configurable pump control preprocessing logic #5

Merged
solipsism merged 34 commits from feature/pump-control-preprocessing into master 2025-11-17 14:23:42 +00:00
2 changed files with 141 additions and 10 deletions
Showing only changes of commit ece4952330 - Show all commits

View File

@ -659,6 +659,31 @@ DASHBOARD_HTML = """
</div> </div>
</div> </div>
<!-- Simplified Protocol Signals Table (for discovery integration) -->
<div class="config-section">
<h3>Protocol Signals (Simplified)</h3>
<p>Signals discovered through protocol discovery will appear here</p>
<div style="margin-top: 20px;">
<table style="width: 100%; border-collapse: collapse;" id="protocol-signals-table">
<thead>
<tr style="background: #f8f9fa;">
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Signal Name</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Protocol Type</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Tags</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Protocol Address</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Database Source</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Status</th>
<th style="padding: 10px; border: 1px solid #ddd; text-align: left;">Actions</th>
</tr>
</thead>
<tbody id="protocol-signals-body">
<!-- Protocol signals will be populated by JavaScript -->
</tbody>
</table>
</div>
</div>
<!-- Add/Edit Mapping Modal --> <!-- Add/Edit Mapping Modal -->
<div id="mapping-modal" class="modal" style="display: none;"> <div id="mapping-modal" class="modal" style="display: none;">
<div class="modal-content"> <div class="modal-content">
@ -717,6 +742,63 @@ DASHBOARD_HTML = """
</form> </form>
</div> </div>
</div> </div>
<!-- Simplified Signal Modal (for discovery integration) -->
<div id="signal-modal" class="modal" style="display: none;">
<div class="modal-content">
<span class="close" onclick="closeSignalModal()">&times;</span>
<h3 id="modal-title">Add Protocol Signal</h3>
<form id="signal-form">
<div class="form-group">
<label for="signal_name">Signal Name *</label>
<input type="text" id="signal_name" name="signal_name" required>
<small style="color: #666;">Human-readable name for this signal (e.g., "Main Pump Speed")</small>
</div>
<div class="form-group">
<label for="tags">Tags</label>
<input type="text" id="tags" name="tags" placeholder="equipment:pump, protocol:modbus_tcp, data_point:speed">
<small style="color: #666;">Comma-separated tags for categorization and filtering</small>
</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 Type</option>
<option value="modbus_tcp">Modbus TCP</option>
<option value="modbus_rtu">Modbus RTU</option>
<option value="opcua">OPC UA</option>
<option value="rest_api">REST API</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>
<small style="color: #666;">Database table and column name (e.g., measurements.pump_speed)</small>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="preprocessing_enabled" name="preprocessing_enabled">
Enable Signal Preprocessing
</label>
</div>
<div class="action-buttons">
<button type="button" onclick="validateSignal()">Validate</button>
<button type="submit" style="background: #28a745;">Save Signal</button>
<button type="button" onclick="closeSignalModal()" style="background: #dc3545;">Cancel</button>
</div>
</form>
</div>
</div>
</div> </div>
<!-- Actions Tab --> <!-- Actions Tab -->

View File

@ -24,7 +24,18 @@ async function loadAllSignals() {
} }
function displaySignals(signals) { function displaySignals(signals) {
const tbody = document.getElementById('protocol-signals-body'); // Try both possible table body IDs
let tbody = document.getElementById('protocol-signals-body');
if (!tbody) {
tbody = document.getElementById('protocol-mappings-body');
}
// Check if the table body element exists
if (!tbody) {
console.warn('protocol signals/mappings table body element not found - table may not be available');
return;
}
tbody.innerHTML = ''; tbody.innerHTML = '';
if (signals.length === 0) { if (signals.length === 0) {
@ -287,14 +298,36 @@ function autoPopulateSignalForm(discoveryData) {
function populateModalFields(discoveryData) { function populateModalFields(discoveryData) {
console.log('Populating modal fields with:', discoveryData); console.log('Populating modal fields with:', discoveryData);
// Populate signal name // Try to find the appropriate form
const signalNameField = document.getElementById('signal_name'); let form = document.getElementById('signal-form');
if (signalNameField && discoveryData.signal_name) { if (!form) {
signalNameField.value = discoveryData.signal_name; form = document.getElementById('mapping-form');
console.log('✓ Set signal_name to:', discoveryData.signal_name);
} }
// Populate tags if (!form) {
console.warn('No signal or mapping form found - cannot auto-populate');
showSimplifiedAlert('No signal form found - please open the add signal/mapping modal first', 'error');
return;
}
// Show the modal if it's hidden
const signalModal = document.getElementById('signal-modal');
const mappingModal = document.getElementById('mapping-modal');
if (signalModal && signalModal.style.display === 'none') {
signalModal.style.display = 'block';
} else if (mappingModal && mappingModal.style.display === 'none') {
mappingModal.style.display = 'block';
}
// Populate signal name (try different field names)
const signalNameField = document.getElementById('signal_name') || document.getElementById('mapping_id');
if (signalNameField && discoveryData.signal_name) {
signalNameField.value = discoveryData.signal_name;
console.log('✓ Set signal name to:', discoveryData.signal_name);
}
// Populate tags (only in simplified template)
const tagsField = document.getElementById('tags'); const tagsField = document.getElementById('tags');
if (tagsField && discoveryData.tags) { if (tagsField && discoveryData.tags) {
tagsField.value = discoveryData.tags.join(', '); tagsField.value = discoveryData.tags.join(', ');
@ -330,7 +363,14 @@ function populateModalFields(discoveryData) {
// Utility Functions // Utility Functions
function showSimplifiedAlert(message, type = 'info') { function showSimplifiedAlert(message, type = 'info') {
const alertsDiv = document.getElementById('simplified-alerts'); const alertsDiv = document.getElementById('protocol-mapping-alerts');
// Check if alerts div exists
if (!alertsDiv) {
console.warn('protocol-mapping-alerts element not found - cannot show alert:', message);
return;
}
const alertDiv = document.createElement('div'); const alertDiv = document.createElement('div');
alertDiv.className = `alert ${type === 'error' ? 'error' : 'success'}`; alertDiv.className = `alert ${type === 'error' ? 'error' : 'success'}`;
alertDiv.textContent = message; alertDiv.textContent = message;
@ -348,7 +388,16 @@ function showSimplifiedAlert(message, type = 'info') {
// Initialize // Initialize
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const signalForm = document.getElementById('signal-form'); // Try both possible form IDs
let signalForm = document.getElementById('signal-form');
if (!signalForm) {
// Look for form inside mapping-modal
const mappingModal = document.getElementById('mapping-modal');
if (mappingModal) {
signalForm = mappingModal.querySelector('form');
}
}
if (signalForm) { if (signalForm) {
signalForm.addEventListener('submit', saveSignal); signalForm.addEventListener('submit', saveSignal);
} }
@ -358,5 +407,5 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
// Expose functions to global scope for discovery integration // Expose functions to global scope for discovery integration
window.autoPopulateSignalForm = autoPopulateSignalForm; window.autoPopulateSignalForm = populateModalFields;
window.loadAllSignals = loadAllSignals; window.loadAllSignals = loadAllSignals;