overheat monitor with auto poweroff

- needs passwordless sudo on target machine or deploy to run as root
This commit is contained in:
Mikkeli Matlock
2026-01-25 19:53:43 +09:00
parent 22e9cd2c43
commit 15a805f7fe
9 changed files with 362 additions and 3 deletions

View File

@@ -0,0 +1,77 @@
import 'dart:async';
import 'config_service.dart';
import 'pi_io.dart';
/// Monitors CPU temperature and triggers overheat condition
///
/// Singleton pattern. Polls temp at 500ms intervals to match dashboard.
/// When temp exceeds threshold for trigger duration, fires callback.
class OverheatMonitor {
OverheatMonitor._();
static final instance = OverheatMonitor._();
Timer? _timer;
int _consecutiveOverheatSamples = 0;
bool _triggered = false;
static const Duration _pollInterval = Duration(milliseconds: 500);
/// Current temperature (from PiIO cache)
double? get currentTemp => PiIO.instance.getTemperature();
/// Whether overheat condition has triggered
bool get isTriggered => _triggered;
/// How long we've been over threshold
Duration get timeOverThreshold =>
Duration(milliseconds: _consecutiveOverheatSamples * _pollInterval.inMilliseconds);
/// Start monitoring with callback when overheat triggers
///
/// [onOverheat] fires once when temp exceeds threshold for configured duration.
/// Safe to call multiple times - restarts monitoring.
void start({required VoidCallback onOverheat}) {
stop();
_triggered = false;
_consecutiveOverheatSamples = 0;
final threshold = ConfigService.instance.overheatThreshold;
final triggerDuration = ConfigService.instance.overheatTriggerDuration;
_timer = Timer.periodic(_pollInterval, (_) {
if (_triggered) return; // Already fired
final temp = PiIO.instance.getTemperature();
if (temp == null) return; // No reading yet
if (temp > threshold) {
_consecutiveOverheatSamples++;
final overThresholdTime = timeOverThreshold;
if (overThresholdTime >= triggerDuration) {
_triggered = true;
onOverheat();
}
} else {
// Temp dropped below threshold - reset counter
_consecutiveOverheatSamples = 0;
}
});
}
/// Stop monitoring
void stop() {
_timer?.cancel();
_timer = null;
}
/// Reset state (for testing/recovery)
void reset() {
_triggered = false;
_consecutiveOverheatSamples = 0;
}
}
/// Callback signature for void functions
typedef VoidCallback = void Function();