class HistoryModel { final double temperature; final double humidity; final double co2; final double pm25; final String overallStatus; final String timestamp; // ac_action sudah dihapus dari script ESP32 terbaru, gunakan default '-' final String acAction; HistoryModel({ required this.temperature, required this.humidity, required this.co2, required this.pm25, required this.overallStatus, required this.timestamp, this.acAction = '-', }); factory HistoryModel.fromMap(Map json) { return HistoryModel( // Support both ESP32 field names and Flutter field names temperature: ((json['temperature'] ?? json['suhu']) ?? 0).toDouble(), humidity: ((json['humidity'] ?? json['kelembapan']) ?? 0).toDouble(), co2: ((json['co2'] ?? json['co2_ppm']) ?? 0).toDouble(), pm25: ((json['pm25'] ?? json['pm25_ugm3']) ?? 0).toDouble(), overallStatus: (json['overall_status'] ?? json['status_keseluruhan'] ?? ''), timestamp: _parseTimestamp(json['timestamp']), // Backward compatible: gunakan ac_action jika ada, jika tidak gunakan '-' acAction: json['ac_action'] ?? '-', ); } Map toMap() { return { 'temperature': temperature, 'humidity': humidity, 'co2': co2, 'pm25': pm25, 'overall_status': overallStatus, 'timestamp': timestamp, 'ac_action': acAction, }; } } String _parseTimestamp(dynamic value) { if (value == null) return ''; if (value is int) { // ESP32 mengirim unix timestamp dalam detik, konversi ke milliseconds // Jika value > 10000000000 berarti sudah dalam milliseconds final timestampMs = value > 10000000000 ? value : value * 1000; final dt = DateTime.fromMillisecondsSinceEpoch(timestampMs); return "${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')} " "${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}"; } return value.toString(); }