Skip to content

Commit c9b53c1

Browse files
Copilotdorkmo
andcommitted
Address PR feedback: improve RPM sensor with multi-second sampling and cleanup
Co-authored-by: dorkmo <1923070+dorkmo@users.noreply.github.com>
1 parent 00d54d3 commit c9b53c1

File tree

2 files changed

+41
-42
lines changed

2 files changed

+41
-42
lines changed

TankAlarm-112025-Client-BluesOpta/TankAlarm-112025-Client-BluesOpta.ino

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,15 @@ static unsigned long gLastRelayCheckMillis = 0;
247247

248248
// RPM sensor state for Hall effect pulse counting
249249
// We track pulses per tank that uses an RPM sensor
250-
static volatile uint32_t gRpmPulseCount[MAX_TANKS] = {0};
250+
static uint32_t gRpmPulseCount[MAX_TANKS] = {0};
251251
static unsigned long gRpmLastSampleMillis[MAX_TANKS] = {0};
252252
static float gRpmLastReading[MAX_TANKS] = {0.0f};
253+
static int gRpmLastPinState[MAX_TANKS] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
254+
255+
// RPM sampling duration in milliseconds (sample for a few seconds each period)
256+
#ifndef RPM_SAMPLE_DURATION_MS
257+
#define RPM_SAMPLE_DURATION_MS 3000
258+
#endif
253259

254260
// Forward declarations
255261
static void initializeStorage();
@@ -1107,59 +1113,49 @@ static float readTankSensor(uint8_t idx) {
11071113
return linearMap(milliamps, 4.0f, 20.0f, 0.0f, cfg.heightInches);
11081114
}
11091115
case SENSOR_HALL_EFFECT_RPM: {
1110-
// Hall effect RPM sensor - non-blocking pulse counting
1116+
// Hall effect RPM sensor - sample pulses for a few seconds each measurement period
11111117
// Use rpmPin if available, otherwise use primaryPin
11121118
int pin = (cfg.rpmPin >= 0 && cfg.rpmPin < 255) ? cfg.rpmPin :
11131119
((cfg.primaryPin >= 0 && cfg.primaryPin < 255) ? cfg.primaryPin : (2 + idx));
11141120

11151121
// Configure pin as input with pullup for Hall effect sensor
11161122
pinMode(pin, INPUT_PULLUP);
11171123

1118-
unsigned long now = millis();
1119-
unsigned long lastSample = gRpmLastSampleMillis[idx];
1124+
// Sample pulses for RPM_SAMPLE_DURATION_MS (default 3 seconds)
1125+
// This provides accurate RPM measurement by counting multiple pulses
1126+
unsigned long sampleStart = millis();
1127+
uint32_t pulseCount = 0;
1128+
int lastState = gRpmLastPinState[idx];
11201129

1121-
// First reading - initialize and return 0
1122-
if (lastSample == 0) {
1123-
gRpmLastSampleMillis[idx] = now;
1124-
gRpmPulseCount[idx] = 0;
1125-
return 0.0f;
1130+
// Initialize lastState from current pin on first reading
1131+
if (gRpmLastSampleMillis[idx] == 0) {
1132+
lastState = digitalRead(pin);
1133+
gRpmLastPinState[idx] = lastState;
11261134
}
11271135

1128-
// Count pulses since last reading (non-blocking quick scan)
1129-
// This reads the current state and counts any transition
1130-
// Note: Static array initialized to HIGH (pullup default state)
1131-
static int lastPinState[MAX_TANKS];
1132-
static bool lastPinStateInit = false;
1133-
if (!lastPinStateInit) {
1134-
for (uint8_t j = 0; j < MAX_TANKS; ++j) {
1135-
lastPinState[j] = HIGH;
1136+
// Count pulses over the sampling duration
1137+
while (millis() - sampleStart < RPM_SAMPLE_DURATION_MS) {
1138+
int currentState = digitalRead(pin);
1139+
// Count falling edges (HIGH to LOW transitions)
1140+
if (lastState == HIGH && currentState == LOW) {
1141+
pulseCount++;
11361142
}
1137-
lastPinStateInit = true;
1143+
lastState = currentState;
1144+
// Small delay to allow other processing and avoid excessive polling
1145+
delay(1);
11381146
}
1139-
int currentState = digitalRead(pin);
11401147

1141-
// Count falling edges (HIGH to LOW transitions)
1142-
if (lastPinState[idx] == HIGH && currentState == LOW) {
1143-
gRpmPulseCount[idx]++;
1144-
}
1145-
lastPinState[idx] = currentState;
1146-
1147-
// Calculate RPM only when sufficient time has passed (1 second minimum)
1148-
unsigned long elapsed = now - lastSample;
1149-
if (elapsed < 1000) {
1150-
// Not enough time elapsed, return last calculated RPM
1151-
return gRpmLastReading[idx];
1152-
}
1148+
// Save last pin state for next sample
1149+
gRpmLastPinState[idx] = lastState;
1150+
gRpmLastSampleMillis[idx] = millis();
11531151

1154-
// Calculate RPM from accumulated pulse count
1155-
// Note: Assumes 1 pulse per revolution (modify divisor for multi-pole magnets)
1156-
// For multi-pole magnets, divide pulse count by number of poles
1157-
uint32_t pulses = gRpmPulseCount[idx];
1158-
float rpm = ((float)pulses * 60000.0f) / (float)elapsed;
1152+
// Calculate RPM from pulse count
1153+
// Formula: RPM = (pulses / sample_duration_seconds) * 60 seconds/minute
1154+
// Simplified: RPM = pulses * 60000 / sample_duration_ms
1155+
// Note: Assumes 1 pulse per revolution (adjust calculation for multi-pole magnets)
1156+
const float MS_PER_MINUTE = 60000.0f;
1157+
float rpm = ((float)pulseCount * MS_PER_MINUTE) / (float)RPM_SAMPLE_DURATION_MS;
11591158

1160-
// Reset for next measurement period
1161-
gRpmLastSampleMillis[idx] = now;
1162-
gRpmPulseCount[idx] = 0;
11631159
gRpmLastReading[idx] = rpm;
11641160

11651161
// Return RPM value (heightInches field is used as max RPM for scaling/alarms)

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,10 +759,13 @@ static const char CONFIG_GENERATOR_HTML[] PROGMEM = R"HTML(
759759
hysteresis: 2.0,
760760
daily: true,
761761
alarmSms: true,
762-
upload: true,
763-
relayTargetClient: relayTarget,
764-
relayMask: relayMask
762+
upload: true
765763
};
764+
// Only include relay control fields when configured
765+
if (relayTarget || relayMask) {
766+
tank.relayTargetClient = relayTarget;
767+
tank.relayMask = relayMask;
768+
}
766769
config.tanks.push(tank);
767770
});
768771

0 commit comments

Comments
 (0)