@@ -428,28 +428,6 @@ struct MonitorRuntime {
428428 unsigned long lastSensorFaultMillis;
429429};
430430
431- // Helper function: Get tank height/capacity based on sensor configuration
432- static float getMonitorHeight (const MonitorConfig &cfg) {
433- if (cfg.sensorInterface == SENSOR_CURRENT_LOOP) {
434- if (cfg.currentLoopType == CURRENT_LOOP_ULTRASONIC) {
435- // For ultrasonic sensors, mount height IS the tank height (distance to bottom)
436- return cfg.sensorMountHeight ;
437- } else {
438- // For pressure sensors, max range + mount height approximates full tank height
439- float rangeInches = cfg.sensorRangeMax * getPressureConversionFactor (cfg.sensorRangeUnit );
440- return rangeInches + cfg.sensorMountHeight ;
441- }
442- } else if (cfg.sensorInterface == SENSOR_ANALOG) {
443- // For analog sensors, max range + mount height approximates full tank height
444- float rangeInches = cfg.sensorRangeMax * getPressureConversionFactor (cfg.sensorRangeUnit );
445- return rangeInches + cfg.sensorMountHeight ;
446- } else if (cfg.sensorInterface == SENSOR_DIGITAL) {
447- // Digital sensors are binary, treat 1.0 as full
448- return 1 .0f ;
449- }
450- return 0 .0f ;
451- }
452-
453431static ClientConfig gConfig ;
454432static MonitorRuntime gMonitorState [MAX_TANKS];
455433
@@ -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