@@ -334,7 +334,7 @@ void test_determineDesiredStateBelowMinCapacityButSurplusWillFullCharge()
334334 systemState.switchEnabled = true ;
335335
336336 bool state = determineState (msg, sizeof (msg));
337- TEST_ASSERT_EQUAL_STRING (" SoC 1% - battery will full charge , but SoC too low" , msg);
337+ TEST_ASSERT_EQUAL_STRING (" SoC 1% - battery will be full charged in ~7h , but SoC too low" , msg);
338338 TEST_ASSERT_FALSE (state);
339339
340340 systemState.ts = TEST_TS + 35 * 3600 ;
@@ -428,6 +428,50 @@ void test_determineDesiredState_BatteryCapacityFinallyAboveMinCapacityButUsocToo
428428 TEST_ASSERT_FALSE (state);
429429}
430430
431+ void test_updateConsumptionStats_Mean ()
432+ {
433+ time_t local_ts0 = (time_t )(TEST_TS + systemState.utc_offset );
434+ struct tm lt0;
435+ gmtime_r (&local_ts0, <0);
436+ int wday = lt0.tm_wday ;
437+ int hour0 = lt0.tm_hour ;
438+ int hour1 = (hour0 + 1 ) % 24 ;
439+ int wday1 = wday;
440+
441+ systemState.ts = TEST_TS ;
442+ systemState.cons_W = 300 ;
443+ updateSystemState (&systemConfig, &systemState);
444+ TEST_ASSERT_EQUAL (0 , systemConfig.cons_stats_Wh [wday][hour0]); // slot not written yet
445+ TEST_ASSERT_EQUAL (300 , systemState.cons_sum_W );
446+ TEST_ASSERT_EQUAL (1 , systemState.cons_count );
447+ int i = 0 ;
448+ for (; i < (55 * 60 * 1000 / SYSTEM_UPDATE_INTERVAL_MS ); i++)
449+ {
450+ updateSystemState (&systemConfig, &systemState);
451+ systemState.ts += SYSTEM_UPDATE_INTERVAL_MS / 1000 ;
452+ }
453+ TEST_ASSERT_EQUAL (300 + 300 * i, systemState.cons_sum_W );
454+ TEST_ASSERT_EQUAL (1 + i, systemState.cons_count );
455+
456+ systemState.cons_W = 4200 ;
457+ int j = 0 ;
458+ for (; j < (5 * 60 * 1000 / SYSTEM_UPDATE_INTERVAL_MS ); j++) // 5min before next hour
459+ {
460+ updateSystemState (&systemConfig, &systemState);
461+ systemState.ts += SYSTEM_UPDATE_INTERVAL_MS / 1000 ;
462+ }
463+ TEST_ASSERT_EQUAL (300 + 300 * i + 4200 * j, systemState.cons_sum_W );
464+ TEST_ASSERT_EQUAL (1 + i + j, systemState.cons_count );
465+
466+ // rollover
467+ systemState.cons_W = 1200 ;
468+ updateSystemState (&systemConfig, &systemState);
469+ systemState.ts += SYSTEM_UPDATE_INTERVAL_MS / 1000 ;
470+ TEST_ASSERT_EQUAL (1200 , systemState.cons_sum_W );
471+ TEST_ASSERT_EQUAL (1 , systemState.cons_count );
472+ TEST_ASSERT_EQUAL (624 , systemConfig.cons_stats_Wh [wday][hour0]); // slot has been written yet
473+ }
474+
431475void test_updateConsumptionStats ()
432476{
433477 // Use TEST_TS local time to find wday/hour of hour being tested (hour 0) and next hour (hour 1)
@@ -437,7 +481,7 @@ void test_updateConsumptionStats()
437481 int wday = lt0.tm_wday ;
438482 int hour0 = lt0.tm_hour ;
439483 int hour1 = (hour0 + 1 ) % 24 ;
440- int wday1 = (hour0 == 23 ) ? (wday + 1 ) % 7 : wday;
484+ int wday1 = wday;
441485
442486 // Accumulate 3 ticks in hour0: 300W, 400W, 500W → mean = 400W
443487 systemState.ts = TEST_TS ;
@@ -454,23 +498,35 @@ void test_updateConsumptionStats()
454498 TEST_ASSERT_EQUAL (0 , systemConfig.cons_stats_Wh [wday][hour0]); // still within same hour
455499
456500 // Advance to hour1 — triggers rollover: slot gets mean of hour0 samples (300+400+500)/3 = 400
457- systemState.ts = TEST_TS + 3600 ;
501+ for (int i = 0 ; i < 750 ; i++)
502+ {
503+ updateSystemState (&systemConfig, &systemState);
504+ }
458505 systemState.cons_W = 200 ;
506+ for (int i = 0 ; i < 750 ; i++)
507+ {
508+ updateSystemState (&systemConfig, &systemState);
509+ }
510+ systemState.ts = TEST_TS + 3600 ;
459511 updateSystemState (&systemConfig, &systemState);
460- TEST_ASSERT_EQUAL (400 , systemConfig.cons_stats_Wh [wday][hour0]); // true mean written
461- TEST_ASSERT_EQUAL (0 , systemConfig.cons_stats_Wh [wday1][hour1]); // hour1 slot not yet written
512+ TEST_ASSERT_EQUAL (350 , systemConfig.cons_stats_Wh [wday][hour0]); // true mean written
513+ TEST_ASSERT_EQUAL (0 , systemConfig.cons_stats_Wh [wday1][hour1]); // hour1 slot not yet written
462514
463515 // Simulate a second occurrence of hour0 (next week): accumulate 200W
464516 systemState.ts = TEST_TS + 7 * 24 * 3600 ; // same weekday, same hour, one week later
465517 systemState.cons_W = 200 ;
466- updateSystemState (&systemConfig, &systemState); // triggers hour1→hour0 rollover (writes hour1, resets)
467- TEST_ASSERT_EQUAL (400 , systemConfig.cons_stats_Wh [wday][hour0]); // unchanged until its own rollover
518+ updateSystemState (&systemConfig, &systemState); // triggers hour1→hour0 rollover (writes hour1, resets)
519+ TEST_ASSERT_EQUAL (350 , systemConfig.cons_stats_Wh [wday][hour0]); // unchanged until its own rollover
468520
469- // Advance past hour0 again: EMA blends 200W mean into existing 400W: (400*9 + 200) / 10 = 380
521+ // Advance past hour0 again: EMA blends 200W mean into existing 350W: (350*9 + 200) / 10 = 335
522+ for (int i = 0 ; i < 1440 ; i++)
523+ {
524+ updateSystemState (&systemConfig, &systemState);
525+ }
470526 systemState.ts = TEST_TS + 7 * 24 * 3600 + 3600 ;
471527 systemState.cons_W = 200 ;
472528 updateSystemState (&systemConfig, &systemState);
473- TEST_ASSERT_EQUAL (380 , systemConfig.cons_stats_Wh [wday][hour0]); // cross-week EMA applied
529+ TEST_ASSERT_EQUAL (335 , systemConfig.cons_stats_Wh [wday][hour0]); // cross-week EMA applied
474530}
475531
476532void test_predictBatteryCapacityStateUsesStats ()
@@ -516,7 +572,9 @@ int main(int argc, char **argv)
516572 UNITY_BEGIN ();
517573
518574 RUN_TEST (test_upateConsumption);
575+ RUN_TEST (test_updateConsumptionStats_Mean);
519576 RUN_TEST (test_updateConsumptionStats);
577+
520578 RUN_TEST (test_predictBatteryCapacityStateNoData);
521579 RUN_TEST (test_predictBatteryCapacityStateSwitchOff);
522580 RUN_TEST (test_predictBatteryCapacityStateSwitchOn);
0 commit comments