feat(secubox-core): Add triple-pulse LED heartbeat with staggered cascade
Implements organic "bump-bump-bump (pause)" pattern across 3 RGB LEDs: - LED1 (health) leads the pulse sequence - LED2 (threat) follows with offset timing (décalé) - LED3 (capacity) trails as final beat in cascade - Smooth intensity transitions between beats - Subtle breathing effect during rest period - Event pulse override preserved for alerts Pattern timing: beat1 → gap → beat2 → gap → beat3 → rest (0.15s ticks) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
301dccec33
commit
a47ae9656c
@ -1094,30 +1094,139 @@ led_event_pulse() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Triple-pulse heartbeat with staggered cascade across LEDs
|
||||
# Creates organic "bump-bump-bump (pause)" pattern
|
||||
# Each LED pulses sequentially with offset timing (décalé)
|
||||
LED_PULSE_PHASE=0 # Tracks which LED is in primary pulse
|
||||
|
||||
led_triple_pulse() {
|
||||
local led_num="$1"
|
||||
local r="$2" g="$3" b="$4"
|
||||
local intensity="$5" # 0-100 for pulse strength
|
||||
|
||||
# Calculate dimmed color based on intensity
|
||||
local ri=$((r * intensity / 100))
|
||||
local gi=$((g * intensity / 100))
|
||||
local bi=$((b * intensity / 100))
|
||||
|
||||
led_set_rgb "$led_num" "$ri" "$gi" "$bi"
|
||||
}
|
||||
|
||||
# Fast LED heartbeat background loop
|
||||
# Runs independently at 1.5s intervals for reactive visual feedback
|
||||
# led1: Global health status
|
||||
# led2: Security threat level
|
||||
# led3: Global capacity meter (CPU + Network) with event pulse overlay
|
||||
# Reads from pre-computed cache files (no subprocess calls)
|
||||
# Runs independently with triple-pulse cascade effect
|
||||
# led1: Global health status (primary pulse)
|
||||
# led2: Security threat level (offset pulse)
|
||||
# led3: Global capacity meter (trailing pulse)
|
||||
# Pattern: bump1-bump2-bump3 (pause) with staggered timing
|
||||
led_heartbeat_loop() {
|
||||
local status_file="/tmp/secubox/led-status"
|
||||
echo "healthy" > "$status_file"
|
||||
|
||||
# Base colors for each LED (set by status)
|
||||
local r1=0 g1=255 b1=0 # Health: green
|
||||
local r2=0 g2=255 b2=0 # Threat: green
|
||||
local r3=0 g3=255 b3=0 # Capacity: green
|
||||
|
||||
# Pulse timing (in 0.1s units for fine control)
|
||||
local beat_gap=1 # Gap between beats in triple
|
||||
local cycle_pause=8 # Pause after triple (longer rest)
|
||||
local tick=0 # Current tick in cycle
|
||||
|
||||
while true; do
|
||||
local status=$(cat "$status_file" 2>/dev/null || echo "healthy")
|
||||
|
||||
# Update RGB LEDs (reads from cache - instant)
|
||||
led_heartbeat "$status"
|
||||
# Update base colors from cache (every cycle start)
|
||||
if [ "$tick" -eq 0 ]; then
|
||||
# LED1: Health color
|
||||
local health=$(get_health_score)
|
||||
if [ "$health" -ge 80 ]; then
|
||||
r1=0; g1=255; b1=50
|
||||
elif [ "$health" -ge 50 ]; then
|
||||
r1=255; g1=200; b1=0
|
||||
else
|
||||
r1=255; g1=30; b1=0
|
||||
fi
|
||||
|
||||
# Check for event pulse first (overrides capacity momentarily)
|
||||
if led_event_pulse; then
|
||||
sleep 0.3 # Brief flash
|
||||
# LED2: Threat color
|
||||
local threat=$(get_threat_level)
|
||||
if [ "$threat" -le 10 ]; then
|
||||
r2=0; g2=255; b2=0
|
||||
elif [ "$threat" -le 40 ]; then
|
||||
r2=200; g2=255; b2=0
|
||||
elif [ "$threat" -le 70 ]; then
|
||||
r2=255; g2=150; b2=0
|
||||
else
|
||||
r2=255; g2=0; b2=0
|
||||
fi
|
||||
|
||||
# LED3: Capacity color (from cache)
|
||||
local cap=$(get_capacity)
|
||||
if [ "$cap" -le 30 ]; then
|
||||
r3=0; g3=255; b3=100
|
||||
elif [ "$cap" -le 60 ]; then
|
||||
r3=100; g3=255; b3=0
|
||||
elif [ "$cap" -le 80 ]; then
|
||||
r3=255; g3=200; b3=0
|
||||
else
|
||||
r3=255; g3=80; b3=0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Global capacity on led3
|
||||
led_global_capacity
|
||||
sleep 1.2
|
||||
# Check for event pulse (overrides normal pattern)
|
||||
if led_event_pulse; then
|
||||
sleep 0.3
|
||||
tick=0
|
||||
continue
|
||||
fi
|
||||
|
||||
# Triple-pulse cascade pattern with décalé (staggered) timing
|
||||
# Cycle: 0=beat1, 1=gap, 2=beat2, 3=gap, 4=beat3, 5-12=rest
|
||||
local total_cycle=$((3 + 2 * beat_gap + cycle_pause))
|
||||
local phase=$((tick % total_cycle))
|
||||
|
||||
# Calculate intensities for each LED based on phase
|
||||
# LED1 leads, LED2 offset by 1 beat, LED3 offset by 2 beats
|
||||
local int1=30 int2=30 int3=30 # Base dim level
|
||||
|
||||
case "$phase" in
|
||||
0) # First beat - LED1 bright, others dim
|
||||
int1=100
|
||||
;;
|
||||
1) # Gap - LED1 fading, LED2 rising
|
||||
int1=60
|
||||
int2=80
|
||||
;;
|
||||
2) # Second beat - LED2 bright, LED1 dim, LED3 rising
|
||||
int1=40
|
||||
int2=100
|
||||
int3=60
|
||||
;;
|
||||
3) # Gap - LED2 fading, LED3 rising
|
||||
int2=60
|
||||
int3=80
|
||||
;;
|
||||
4) # Third beat - LED3 bright, others dim
|
||||
int3=100
|
||||
;;
|
||||
5) # Post-triple fade
|
||||
int1=20; int2=20; int3=50
|
||||
;;
|
||||
*) # Rest period - all dim with subtle breathing
|
||||
local breath=$((30 + (phase % 3) * 5))
|
||||
int1=$breath; int2=$breath; int3=$breath
|
||||
;;
|
||||
esac
|
||||
|
||||
# Apply intensities
|
||||
led_triple_pulse 1 "$r1" "$g1" "$b1" "$int1"
|
||||
led_triple_pulse 2 "$r2" "$g2" "$b2" "$int2"
|
||||
led_triple_pulse 3 "$r3" "$g3" "$b3" "$int3"
|
||||
|
||||
tick=$((tick + 1))
|
||||
[ "$tick" -ge "$total_cycle" ] && tick=0
|
||||
|
||||
# Fine timing: 0.15s per tick for smooth animation
|
||||
sleep 0.15
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user