Drive splash animations by session usage rate
Group splash animations into four moods (idle/normal/active/heavy) and pick which group plays based on a 5-min sliding rate of session_pct. Thresholds sit at 0.10/0.20/0.33 %/min so Heavy fires when usage matches or beats the 5-hour session reset pace. Splash auto-rotates within the current group every 20s; group recomputes on every BLE poll and the splash re-picks immediately if it changes mid-display. 4-min minimum window prevents single-sample bumps after boot from falsely landing in Heavy.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
#include "usage_rate.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
// Thresholds in %/min. A 5-hour (300 min) session ÷ 100% = 0.33 %/min to fill
|
||||
// exactly at the same pace as the session itself resets — the user wants the
|
||||
// "heavy" tier to start right there (filling in 4–5 hours).
|
||||
// < 0.10 → Idle (17h+ to fill, basically dormant)
|
||||
// < 0.20 → Normal (8–17h to fill, slow steady use)
|
||||
// < 0.33 → Active (5–8h, heavy but not yet pace-matching)
|
||||
// >=0.33 → Heavy (≤5h, matching or beating the session reset)
|
||||
#define RATE_THRESH_NORMAL 0.10f
|
||||
#define RATE_THRESH_ACTIVE 0.20f
|
||||
#define RATE_THRESH_HEAVY 0.33f
|
||||
|
||||
// Minimum span between oldest and newest sample before we trust the computed
|
||||
// rate. The whole point of the ring buffer is to smooth out single-sample
|
||||
// jitter — at 60s daemon polling, a 1% bump between two consecutive samples
|
||||
// looks like 1 %/min (Heavy) but really just means you grew 1% in the last
|
||||
// minute. We require ~4 min of accumulated history so the rate reflects a
|
||||
// real trend, not one noisy delta. Side-effect: ~4 min warm-up after boot
|
||||
// during which we report Idle.
|
||||
#define MIN_WINDOW_MS 240000UL
|
||||
|
||||
#define RING_SIZE 6
|
||||
|
||||
struct Sample { uint32_t ms; float pct; };
|
||||
|
||||
static Sample ring[RING_SIZE];
|
||||
static uint8_t count = 0;
|
||||
static uint8_t head = 0; // index of next write slot
|
||||
|
||||
static inline uint8_t oldest_idx(void) {
|
||||
return (head + RING_SIZE - count) % RING_SIZE;
|
||||
}
|
||||
|
||||
void usage_rate_reset(void) {
|
||||
count = 0;
|
||||
head = 0;
|
||||
}
|
||||
|
||||
void usage_rate_sample(float session_pct) {
|
||||
uint32_t now = millis();
|
||||
|
||||
if (count > 0) {
|
||||
uint8_t latest = (head + RING_SIZE - 1) % RING_SIZE;
|
||||
// Session reset: pct dropped substantially. Restart tracking.
|
||||
if (session_pct + 5.0f < ring[latest].pct) {
|
||||
usage_rate_reset();
|
||||
}
|
||||
}
|
||||
|
||||
ring[head] = { now, session_pct };
|
||||
head = (head + 1) % RING_SIZE;
|
||||
if (count < RING_SIZE) count++;
|
||||
}
|
||||
|
||||
int usage_rate_group(void) {
|
||||
if (count < 2) return 0;
|
||||
|
||||
uint8_t o = oldest_idx();
|
||||
uint8_t l = (head + RING_SIZE - 1) % RING_SIZE;
|
||||
uint32_t dt = ring[l].ms - ring[o].ms;
|
||||
if (dt < MIN_WINDOW_MS) return 0;
|
||||
|
||||
float dp = ring[l].pct - ring[o].pct;
|
||||
if (dp < 0.0f) dp = 0.0f;
|
||||
float rate = dp * 60000.0f / (float)dt;
|
||||
|
||||
if (rate < RATE_THRESH_NORMAL) return 0;
|
||||
if (rate < RATE_THRESH_ACTIVE) return 1;
|
||||
if (rate < RATE_THRESH_HEAVY) return 2;
|
||||
return 3;
|
||||
}
|
||||
Reference in New Issue
Block a user