78 lines
2.2 KiB
Dart
78 lines
2.2 KiB
Dart
|
|
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();
|