108 lines
4.0 KiB
Dart
108 lines
4.0 KiB
Dart
import 'dart:async';
|
|
import 'dart:math';
|
|
|
|
/// 📌 [독립 함수] 지난 24시간 치의 가상(더미) 온도 데이터 리스트를 생성한다.
|
|
///
|
|
/// 실제 DB 연동 전, 개발 단계에서 차트/리스트 UI를 채우기 위한 용도입니다.
|
|
/// 값이 들쭉날쭉 튀지 않고 자연스럽게 보이도록, 직전 값에서 조금씩만
|
|
/// 변하는 "랜덤 워크(random walk)" 방식으로 만듭니다.
|
|
///
|
|
/// - [count] : 만들 데이터 개수 (기본 24개 = 1시간 간격 24시간)
|
|
/// - [minTemp] : 가상 온도 하한
|
|
/// - [maxTemp] : 가상 온도 상한
|
|
List<double> generateDummyTemperatures({
|
|
int count = 24,
|
|
double minTemp = 18.0,
|
|
double maxTemp = 28.0,
|
|
}) {
|
|
final random = Random();
|
|
final list = <double>[];
|
|
|
|
// 시작 온도는 범위 내 임의 값
|
|
double last = minTemp + random.nextDouble() * (maxTemp - minTemp);
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
// 직전 값에서 -0.5 ~ +0.5°C 내외로 흔들기 (clamp는 num 반환 → toDouble)
|
|
last = (last + (random.nextDouble() - 0.5)).clamp(minTemp, maxTemp).toDouble();
|
|
list.add(double.parse(last.toStringAsFixed(1))); // 소수점 1자리로 정리
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/// 📡 [스트림 서비스] 앱이 켜져 있는 동안 일정 주기마다
|
|
/// 새로운 가상 온도 데이터를 계속 추가하며 갱신된 리스트를 흘려보낸다.
|
|
///
|
|
/// 사용 흐름:
|
|
/// final service = TempDataService()..start();
|
|
/// service.stream.listen((temps) { ... }); // StreamBuilder로 구독
|
|
/// service.dispose(); // 화면이 사라질 때 반드시 호출
|
|
///
|
|
/// 👉 나중에 실제 DB 연동 시에는 [_generateNextTemperature] 내부만
|
|
/// "DB에서 최신 온도 1건 조회" 로직으로 교체하면 됩니다.
|
|
class TempDataService {
|
|
TempDataService({
|
|
this.minTemp = 18.0,
|
|
this.maxTemp = 28.0,
|
|
this.historyCount = 24,
|
|
this.interval = const Duration(seconds: 3), // ⏱️ 테스트용 3초
|
|
this.maxLength = 200, // 메모리 무한 증가 방지용 보관 한도
|
|
});
|
|
|
|
final double minTemp; // 최저 가상 온도
|
|
final double maxTemp; // 최고 가상 온도
|
|
final int historyCount; // 시작 시 채워둘 24시간 데이터 개수
|
|
final Duration interval; // 새 데이터 추가 주기
|
|
final int maxLength; // 리스트에 보관할 최대 개수
|
|
|
|
final _random = Random();
|
|
final List<double> _temperatures = [];
|
|
Timer? _timer;
|
|
|
|
// broadcast: 여러 위젯이 동시에 구독할 수 있게 함
|
|
final _controller = StreamController<List<double>>.broadcast();
|
|
|
|
/// 갱신될 때마다 "전체 온도 리스트"가 흘러나오는 스트림
|
|
Stream<List<double>> get stream => _controller.stream;
|
|
|
|
/// 현재까지 쌓인 데이터 (읽기 전용 복사본)
|
|
List<double> get current => List.unmodifiable(_temperatures);
|
|
|
|
/// 스트림 시작: 24시간 더미 데이터로 시드한 뒤, [interval]마다 새 값 추가
|
|
void start() {
|
|
_temperatures
|
|
..clear()
|
|
..addAll(generateDummyTemperatures(
|
|
count: historyCount,
|
|
minTemp: minTemp,
|
|
maxTemp: maxTemp,
|
|
));
|
|
_controller.add(current); // 초기 데이터를 즉시 한 번 전달
|
|
|
|
_timer?.cancel();
|
|
_timer = Timer.periodic(interval, (_) {
|
|
_temperatures.add(_generateNextTemperature());
|
|
|
|
// 오래된 데이터부터 버려서 길이 유지
|
|
while (_temperatures.length > maxLength) {
|
|
_temperatures.removeAt(0);
|
|
}
|
|
_controller.add(current);
|
|
});
|
|
}
|
|
|
|
/// 다음(새) 가상 온도 한 건을 생성한다. 직전 값 기준 랜덤 워크.
|
|
double _generateNextTemperature() {
|
|
final last = _temperatures.isEmpty
|
|
? minTemp + _random.nextDouble() * (maxTemp - minTemp)
|
|
: _temperatures.last;
|
|
final next = (last + (_random.nextDouble() - 0.5)).clamp(minTemp, maxTemp);
|
|
return double.parse(next.toStringAsFixed(1));
|
|
}
|
|
|
|
/// 타이머 정지 + 스트림 정리. 위젯 dispose() 에서 꼭 호출할 것.
|
|
void dispose() {
|
|
_timer?.cancel();
|
|
_controller.close();
|
|
}
|
|
}
|