Skip to content

Commit 558840f

Browse files
Copilotdorkmo
andcommitted
Auto-calculate mA sensor reading from telemetry history
Co-authored-by: dorkmo <[email protected]>
1 parent d9e6b8f commit 558840f

File tree

1 file changed

+65
-15
lines changed

1 file changed

+65
-15
lines changed

TankAlarm-112025-Server-BluesOpta/TankAlarm-112025-Server-BluesOpta.ino

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)