@@ -276,28 +276,6 @@ static float getDistanceConversionFactor(const char* unit) {
276276 return 1 .0f ; // Default: assume inches
277277}
278278
279- // Helper function: Get tank height/capacity based on sensor configuration
280- static float getMonitorHeight (const MonitorConfig &cfg) {
281- if (cfg.sensorInterface == SENSOR_CURRENT_LOOP) {
282- if (cfg.currentLoopType == CURRENT_LOOP_ULTRASONIC) {
283- // For ultrasonic sensors, mount height IS the tank height (distance to bottom)
284- return cfg.sensorMountHeight ;
285- } else {
286- // For pressure sensors, max range + mount height approximates full tank height
287- float rangeInches = cfg.sensorRangeMax * getPressureConversionFactor (cfg.sensorRangeUnit );
288- return rangeInches + cfg.sensorMountHeight ;
289- }
290- } else if (cfg.sensorInterface == SENSOR_ANALOG) {
291- // For analog sensors, max range + mount height approximates full tank height
292- float rangeInches = cfg.sensorRangeMax * getPressureConversionFactor (cfg.sensorRangeUnit );
293- return rangeInches + cfg.sensorMountHeight ;
294- } else if (cfg.sensorInterface == SENSOR_DIGITAL) {
295- // Digital sensors are binary, treat 1.0 as full
296- return 1 .0f ;
297- }
298- return 0 .0f ;
299- }
300-
301279static const uint8_t NOTECARD_I2C_ADDRESS = 0x17 ;
302280static const uint32_t NOTECARD_I2C_FREQUENCY = 400000UL ;
303281
@@ -517,45 +495,6 @@ struct PulseSamplingRecommendation {
517495 const char *description; // Human-readable description
518496};
519497
520- static PulseSamplingRecommendation getRecommendedPulseSampling (float expectedRate) {
521- PulseSamplingRecommendation rec;
522-
523- if (expectedRate <= 0 .0f ) {
524- // No expected rate configured - use defaults
525- rec.sampleDurationMs = RPM_SAMPLE_DURATION_MS;
526- rec.accumulatedMode = false ;
527- rec.description = " Default (60s sample)" ;
528- } else if (expectedRate < 1 .0f ) {
529- // Very low rate (< 1 RPM/GPM): use accumulated mode
530- // Count pulses over entire telemetry interval for accuracy
531- rec.sampleDurationMs = 60000 ; // 60s sample within each interval
532- rec.accumulatedMode = true ;
533- rec.description = " Accumulated mode (very low rate)" ;
534- } else if (expectedRate < 10 .0f ) {
535- // Low rate (1-10 RPM/GPM): longer sample for accuracy
536- rec.sampleDurationMs = 60000 ; // 60 seconds
537- rec.accumulatedMode = false ;
538- rec.description = " 60s sample (low rate)" ;
539- } else if (expectedRate < 100 .0f ) {
540- // Medium rate (10-100 RPM/GPM): moderate sample
541- rec.sampleDurationMs = 30000 ; // 30 seconds
542- rec.accumulatedMode = false ;
543- rec.description = " 30s sample (medium rate)" ;
544- } else if (expectedRate < 1000 .0f ) {
545- // High rate (100-1000 RPM/GPM): shorter sample is sufficient
546- rec.sampleDurationMs = 10000 ; // 10 seconds
547- rec.accumulatedMode = false ;
548- rec.description = " 10s sample (high rate)" ;
549- } else {
550- // Very high rate (> 1000 RPM): quick sample
551- rec.sampleDurationMs = 3000 ; // 3 seconds
552- rec.accumulatedMode = false ;
553- rec.description = " 3s sample (very high rate)" ;
554- }
555-
556- return rec;
557- }
558-
559498// Serial log buffer structure for client
560499struct SerialLogEntry {
561500 double timestamp;
@@ -572,6 +511,8 @@ static ClientSerialLog gSerialLog;
572511static unsigned long gLastSerialRequestCheckMillis = 0 ;
573512
574513// Forward declarations
514+ static PulseSamplingRecommendation getRecommendedPulseSampling (float expectedRate);
515+ static float getMonitorHeight (const MonitorConfig &cfg);
575516static void initializeStorage ();
576517static void ensureConfigLoaded ();
577518static void createDefaultConfig (ClientConfig &cfg);
@@ -789,6 +730,70 @@ void loop() {
789730 #endif
790731}
791732
733+ // Helper: Get recommended pulse sampling parameters based on expected rate
734+ // This helps configure optimal sampling for the expected RPM/flow rate range
735+ // Returns: pulseSampleDurationMs, pulseAccumulatedMode recommendations
736+ static PulseSamplingRecommendation getRecommendedPulseSampling (float expectedRate) {
737+ PulseSamplingRecommendation rec;
738+
739+ if (expectedRate <= 0 .0f ) {
740+ // No expected rate configured - use defaults
741+ rec.sampleDurationMs = RPM_SAMPLE_DURATION_MS;
742+ rec.accumulatedMode = false ;
743+ rec.description = " Default (60s sample)" ;
744+ } else if (expectedRate < 1 .0f ) {
745+ // Very low rate (< 1 RPM/GPM): use accumulated mode
746+ // Count pulses over entire telemetry interval for accuracy
747+ rec.sampleDurationMs = 60000 ; // 60s sample within each interval
748+ rec.accumulatedMode = true ;
749+ rec.description = " Accumulated mode (very low rate)" ;
750+ } else if (expectedRate < 10 .0f ) {
751+ // Low rate (1-10 RPM/GPM): longer sample for accuracy
752+ rec.sampleDurationMs = 60000 ; // 60 seconds
753+ rec.accumulatedMode = false ;
754+ rec.description = " 60s sample (low rate)" ;
755+ } else if (expectedRate < 100 .0f ) {
756+ // Medium rate (10-100 RPM/GPM): moderate sample
757+ rec.sampleDurationMs = 30000 ; // 30 seconds
758+ rec.accumulatedMode = false ;
759+ rec.description = " 30s sample (medium rate)" ;
760+ } else if (expectedRate < 1000 .0f ) {
761+ // High rate (100-1000 RPM/GPM): shorter sample is sufficient
762+ rec.sampleDurationMs = 10000 ; // 10 seconds
763+ rec.accumulatedMode = false ;
764+ rec.description = " 10s sample (high rate)" ;
765+ } else {
766+ // Very high rate (> 1000 RPM): quick sample
767+ rec.sampleDurationMs = 3000 ; // 3 seconds
768+ rec.accumulatedMode = false ;
769+ rec.description = " 3s sample (very high rate)" ;
770+ }
771+
772+ return rec;
773+ }
774+
775+ // Helper function: Get tank height/capacity based on sensor configuration
776+ static float getMonitorHeight (const MonitorConfig &cfg) {
777+ if (cfg.sensorInterface == SENSOR_CURRENT_LOOP) {
778+ if (cfg.currentLoopType == CURRENT_LOOP_ULTRASONIC) {
779+ // For ultrasonic sensors, mount height IS the tank height (distance to bottom)
780+ return cfg.sensorMountHeight ;
781+ } else {
782+ // For pressure sensors, max range + mount height approximates full tank height
783+ float rangeInches = cfg.sensorRangeMax * getPressureConversionFactor (cfg.sensorRangeUnit );
784+ return rangeInches + cfg.sensorMountHeight ;
785+ }
786+ } else if (cfg.sensorInterface == SENSOR_ANALOG) {
787+ // For analog sensors, max range + mount height approximates full tank height
788+ float rangeInches = cfg.sensorRangeMax * getPressureConversionFactor (cfg.sensorRangeUnit );
789+ return rangeInches + cfg.sensorMountHeight ;
790+ } else if (cfg.sensorInterface == SENSOR_DIGITAL) {
791+ // Digital sensors are binary, treat 1.0 as full
792+ return 1 .0f ;
793+ }
794+ return 0 .0f ;
795+ }
796+
792797static void initializeStorage () {
793798#ifdef FILESYSTEM_AVAILABLE
794799 #if defined(ARDUINO_OPTA) || defined(ARDUINO_ARCH_MBED)
0 commit comments