@@ -2603,8 +2603,9 @@ static const char CALIBRATION_HTML[] PROGMEM = R"HTML(
26032603 </div>
26042604 </label>
26052605 <label class="field">
2606- <span>Current Sensor Reading (mA) <em style="font-weight: normal; color: var(--muted);">- Required for calibration</em></span>
2607- <input type="number" id="sensorReading" step="0.01" min="4" max="20" placeholder="e.g., 12.5 (4-20mA range)">
2606+ <span>Sensor Reading (mA) <em style="font-weight: normal; color: var(--muted);">- Auto-calculated from telemetry</em></span>
2607+ <input type="number" id="sensorReading" step="0.01" min="4" max="20" placeholder="Auto-filled when tank selected">
2608+ <small id="sensorAutoInfo" style="color: var(--muted); margin-top: 4px; display: block;"></small>
26082609 </label>
26092610 <label class="field">
26102611 <span>Reading Timestamp</span>
@@ -2623,7 +2624,7 @@ static const char CALIBRATION_HTML[] PROGMEM = R"HTML(
26232624 <div class="info-box">
26242625 <strong>How it works:</strong> Each calibration reading pairs a verified tank level (measured with a stick gauge, sight glass, or other method) with the current 4-20mA sensor reading. With at least 2 data points at different levels, the system calculates a linear regression to determine the actual relationship between sensor output and tank level. This learned calibration replaces the theoretical maxValue-based calculation.
26252626 <br><br>
2626- <strong>Important :</strong> The sensor reading (mA) is required for calibration learning. If not provided, the entry will be logged but won't contribute to the calibration calculation. You can read the mA value from your 4-20mA loop meter or the sensor's display .
2627+ <strong>Sensor reading auto-calculation :</strong> When you select a tank, the sensor reading (mA) is automatically calculated from the latest telemetry data. You can override this value if you have a more accurate reading from a loop meter.
26272628 </div>
26282629 </div>
26292630
@@ -2791,7 +2792,11 @@ static const char CALIBRATION_HTML[] PROGMEM = R"HTML(
27912792 client: t.client,
27922793 tank: t.tank,
27932794 site: t.site,
2794- label: t.label || `Tank ${t.tank}`
2795+ label: t.label || `Tank ${t.tank}`,
2796+ heightInches: t.heightInches || 0,
2797+ levelInches: t.levelInches || 0,
2798+ percent: t.percent || 0,
2799+ lastUpdate: t.lastUpdate || 0
27952800 });
27962801 }
27972802 });
@@ -2805,6 +2810,44 @@ static const char CALIBRATION_HTML[] PROGMEM = R"HTML(
28052810 });
28062811 }
28072812
2813+ // Calculate estimated mA from tank percent (for 4-20mA pressure sensors)
2814+ function estimateSensorMa(percent) {
2815+ if (typeof percent !== 'number' || !isFinite(percent)) return 0;
2816+ // Clamp percent to 0-100 range
2817+ const clampedPercent = Math.max(0, Math.min(100, percent));
2818+ // 4mA = 0%, 20mA = 100%
2819+ return 4 + (clampedPercent / 100) * 16;
2820+ }
2821+
2822+ // Auto-populate sensor reading when tank is selected
2823+ function onTankSelect() {
2824+ const tankKey = document.getElementById('tankSelect').value;
2825+ const sensorInput = document.getElementById('sensorReading');
2826+ const sensorInfo = document.getElementById('sensorAutoInfo');
2827+
2828+ if (!tankKey) {
2829+ sensorInput.value = '';
2830+ if (sensorInfo) sensorInfo.textContent = '';
2831+ return;
2832+ }
2833+
2834+ // Find the tank data
2835+ const tank = tanks.find(t => `${t.client}:${t.tank}` === tankKey);
2836+ if (tank && tank.heightInches > 0) {
2837+ const estimatedMa = estimateSensorMa(tank.percent);
2838+ if (estimatedMa >= 4 && estimatedMa <= 20) {
2839+ sensorInput.value = estimatedMa.toFixed(2);
2840+ if (sensorInfo) {
2841+ const lastUpdateDate = tank.lastUpdate ? new Date(tank.lastUpdate * 1000).toLocaleString() : 'unknown';
2842+ sensorInfo.textContent = `Auto-calculated from last telemetry (${tank.percent.toFixed(1)}% @ ${lastUpdateDate})`;
2843+ }
2844+ }
2845+ }
2846+ }
2847+
2848+ // Attach tank select handler
2849+ document.getElementById('tankSelect').addEventListener('change', onTankSelect);
2850+
28082851 // Load calibration data
28092852 async function loadCalibrationData() {
28102853 try {
@@ -7699,21 +7742,28 @@ static void handleCalibrationPost(EthernetClient &client, const String &body) {
76997742 // Optional fields
77007743 float sensorReading = doc[" sensorReading" ].as <float >();
77017744 if (!doc.containsKey (" sensorReading" ) || sensorReading < 4 .0f || sensorReading > 20 .0f ) {
7702- // Try to get current sensor reading from tank records
7703- sensorReading = 0 .0f ; // Will be marked as manual entry without sensor reading
7745+ // Auto-calculate sensor reading from tank telemetry data
7746+ sensorReading = 0 .0f ;
77047747
7705- // Look up current tank reading if available
7748+ // Look up tank record to get percent from latest telemetry
77067749 for (uint8_t i = 0 ; i < gTankRecordCount ; ++i) {
77077750 if (strcmp (gTankRecords [i].clientUid , clientUid) == 0 &&
77087751 gTankRecords [i].tankNumber == tankNumber) {
7709- // Estimate mA from current level if we have height data
7710- // This is approximate - better to have actual sensor reading
7711- if (gTankRecords [i].heightInches > 1 .0f ) { // Require at least 1 inch height for safe division
7712- float percent = gTankRecords [i].levelInches / gTankRecords [i].heightInches ;
7713- // Clamp percent to valid range
7714- if (percent < 0 .0f ) percent = 0 .0f ;
7715- if (percent > 1 .0f ) percent = 1 .0f ;
7716- sensorReading = 4 .0f + percent * 16 .0f ; // Estimate 4-20mA from percent
7752+ // Use stored percent if available, otherwise calculate from level/height
7753+ float percent = gTankRecords [i].percent ;
7754+ if (percent < 0 .1f && gTankRecords [i].heightInches > 1 .0f ) {
7755+ // Calculate percent from level/height as fallback
7756+ percent = (gTankRecords [i].levelInches / gTankRecords [i].heightInches ) * 100 .0f ;
7757+ }
7758+ // Convert percent (0-100) to mA (4-20)
7759+ if (percent >= 0 .0f ) {
7760+ if (percent > 100 .0f ) percent = 100 .0f ;
7761+ sensorReading = 4 .0f + (percent / 100 .0f ) * 16 .0f ;
7762+ Serial.print (F (" Auto-calculated sensor reading from telemetry: " ));
7763+ Serial.print (sensorReading, 2 );
7764+ Serial.print (F (" mA (" ));
7765+ Serial.print (percent, 1 );
7766+ Serial.println (F (" %)" ));
77177767 }
77187768 break ;
77197769 }
0 commit comments