准备更新temp_avg相关字段能力
This commit is contained in:
@@ -45,6 +45,7 @@ class _BatteryHealthPageState extends State<BatteryHealthPage> {
|
||||
String _deviceModel = "魅族21 Pro (默认)";
|
||||
double _maxTemp = 0;
|
||||
double _minTemp = 0;
|
||||
double _batteryTempAvg = 0;
|
||||
double _maxVolt = 0;
|
||||
double _minVolt = 0;
|
||||
bool _hasData = false;
|
||||
@@ -359,6 +360,7 @@ class _BatteryHealthPageState extends State<BatteryHealthPage> {
|
||||
final volt = _extractVolt(lastLine);
|
||||
final (maxTemp, minTemp) = _extractTempExtremes(validLines);
|
||||
final (maxVolt, minVolt) = _extractVoltExtremes(validLines);
|
||||
final tempAvg = _extractTempAvg(validLines);
|
||||
|
||||
dev.log(
|
||||
'🔵 字段提取: cycle=$cycle, temp=$temp, volt=$volt',
|
||||
@@ -390,6 +392,7 @@ class _BatteryHealthPageState extends State<BatteryHealthPage> {
|
||||
_currentCap = (validatedCap ?? _currentCap).toDouble();
|
||||
_cycleCount = cycle;
|
||||
_batteryTemp = temp;
|
||||
_batteryTempAvg = tempAvg;
|
||||
_batteryVolt = volt;
|
||||
_maxTemp = maxTemp;
|
||||
_minTemp = minTemp;
|
||||
@@ -494,6 +497,20 @@ class _BatteryHealthPageState extends State<BatteryHealthPage> {
|
||||
return (maxTemp ?? 0, minTemp ?? 0);
|
||||
}
|
||||
|
||||
double _extractTempAvg(List<String> lines) {
|
||||
final reg = RegExp(r'tbat=(\d+)');
|
||||
double sum = 0;
|
||||
int count = 0;
|
||||
for (String line in lines) {
|
||||
final match = reg.firstMatch(line);
|
||||
if (match != null) {
|
||||
sum += double.parse(match.group(1)!);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count > 0 ? sum / count : 0;
|
||||
}
|
||||
|
||||
(double, double) _extractVoltExtremes(List<String> lines) {
|
||||
final reg = RegExp(r'vbat=(\d+)');
|
||||
double? maxVolt, minVolt;
|
||||
@@ -773,6 +790,7 @@ class _BatteryHealthPageState extends State<BatteryHealthPage> {
|
||||
child: BatteryInfoPanel(
|
||||
batteryVolt: _batteryVolt,
|
||||
batteryTemp: _batteryTemp,
|
||||
tempAvg: _batteryTempAvg,
|
||||
maxVolt: _maxVolt,
|
||||
minVolt: _minVolt,
|
||||
maxTemp: _maxTemp,
|
||||
|
||||
@@ -87,25 +87,39 @@ class BatteryDataService {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 提取电压极值
|
||||
// 提取电压极值与平均温度
|
||||
final voltReg = RegExp(r'vbat=(\d+)');
|
||||
final tempReg = RegExp(r'tbat=(\d+)');
|
||||
double? maxVolt, minVolt;
|
||||
double tempSum = 0;
|
||||
int tempCount = 0;
|
||||
|
||||
for (String line in lines) {
|
||||
if (!line.contains('tbat=')) continue;
|
||||
final match = voltReg.firstMatch(line);
|
||||
if (match != null) {
|
||||
final v = int.parse(match.group(1)!) / 1000000;
|
||||
|
||||
final vMatch = voltReg.firstMatch(line);
|
||||
if (vMatch != null) {
|
||||
final v = int.parse(vMatch.group(1)!) / 1000000;
|
||||
if (maxVolt == null || v > maxVolt) maxVolt = v;
|
||||
if (minVolt == null || v < minVolt) minVolt = v;
|
||||
}
|
||||
|
||||
final tMatch = tempReg.firstMatch(line);
|
||||
if (tMatch != null) {
|
||||
tempSum += double.parse(tMatch.group(1)!);
|
||||
tempCount++;
|
||||
}
|
||||
}
|
||||
if (maxVolt == null || minVolt == null) continue;
|
||||
|
||||
final tempAvg = tempCount > 0 ? tempSum / tempCount : 0.0;
|
||||
|
||||
await _dbService.insertOrUpdate(
|
||||
dateStr,
|
||||
validatedCap,
|
||||
maxVolt,
|
||||
minVolt,
|
||||
tempAvg: tempAvg, // 🆕
|
||||
);
|
||||
dev.log(
|
||||
'🔵 插入数据库: $dateStr, cap=$validatedCap',
|
||||
|
||||
@@ -6,22 +6,21 @@ import 'package:path/path.dart';
|
||||
class DatabaseService {
|
||||
static Database? _database;
|
||||
static const String _tableName = 'battery_data';
|
||||
static const int _dbVersion = 2; // 🆕 1.7.1 加入 temp_avg
|
||||
|
||||
/// 获取数据库实例(单例)
|
||||
Future<Database> get database async {
|
||||
if (_database != null) return _database!;
|
||||
_database = await _initDatabase();
|
||||
return _database!;
|
||||
}
|
||||
|
||||
/// 初始化数据库
|
||||
Future<Database> _initDatabase() async {
|
||||
final dbPath = await getDatabasesPath();
|
||||
final path = join(dbPath, 'battery_health.db');
|
||||
|
||||
return await openDatabase(
|
||||
path,
|
||||
version: 1,
|
||||
version: _dbVersion,
|
||||
onCreate: (db, version) async {
|
||||
await db.execute('''
|
||||
CREATE TABLE $_tableName (
|
||||
@@ -29,6 +28,7 @@ class DatabaseService {
|
||||
capacity INTEGER NOT NULL,
|
||||
volt_max REAL NOT NULL,
|
||||
volt_min REAL NOT NULL,
|
||||
temp_avg REAL NOT NULL DEFAULT 0,
|
||||
updated_at TEXT NOT NULL
|
||||
)
|
||||
''');
|
||||
@@ -37,6 +37,15 @@ class DatabaseService {
|
||||
''');
|
||||
dev.log('✅ 数据库表创建成功', name: 'DatabaseService');
|
||||
},
|
||||
onUpgrade: (db, oldVersion, newVersion) async {
|
||||
// 🆕 1.7.1 v1 -> v2:添加 temp_avg 字段
|
||||
if (oldVersion < 2) {
|
||||
await db.execute(
|
||||
'ALTER TABLE $_tableName ADD COLUMN temp_avg REAL NOT NULL DEFAULT 0',
|
||||
);
|
||||
dev.log('✅ 数据库升级 v1->v2:已添加 temp_avg 字段', name: 'DatabaseService');
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,8 +54,9 @@ class DatabaseService {
|
||||
String date,
|
||||
int capacity,
|
||||
double voltMax,
|
||||
double voltMin,
|
||||
) async {
|
||||
double voltMin, {
|
||||
double tempAvg = 0, // 🆕
|
||||
}) async {
|
||||
final db = await database;
|
||||
final now = DateTime.now().toIso8601String();
|
||||
|
||||
@@ -55,9 +65,13 @@ class DatabaseService {
|
||||
'capacity': capacity,
|
||||
'volt_max': voltMax,
|
||||
'volt_min': voltMin,
|
||||
'temp_avg': tempAvg,
|
||||
'updated_at': now,
|
||||
}, conflictAlgorithm: ConflictAlgorithm.replace);
|
||||
dev.log('📝 数据已保存: $date, cap=$capacity', name: 'DatabaseService');
|
||||
dev.log(
|
||||
'📝 数据已保存: $date, cap=$capacity, tempAvg=${tempAvg.toStringAsFixed(1)}',
|
||||
name: 'DatabaseService',
|
||||
);
|
||||
}
|
||||
|
||||
/// 查询最近 N 条数据(按日期倒序)
|
||||
|
||||
@@ -11,6 +11,8 @@ class BatteryInfoPanel extends StatelessWidget {
|
||||
final double minTemp;
|
||||
final DataAbnormalType abnormalType;
|
||||
|
||||
final double tempAvg;
|
||||
|
||||
const BatteryInfoPanel({
|
||||
super.key,
|
||||
required this.batteryVolt,
|
||||
@@ -19,6 +21,7 @@ class BatteryInfoPanel extends StatelessWidget {
|
||||
required this.minVolt,
|
||||
required this.maxTemp,
|
||||
required this.minTemp,
|
||||
this.tempAvg = 0,
|
||||
this.abnormalType = DataAbnormalType.none,
|
||||
});
|
||||
|
||||
@@ -110,13 +113,14 @@ class BatteryInfoPanel extends StatelessWidget {
|
||||
'${batteryTemp.toStringAsFixed(0)}℃',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// 🆕 一行显示:↑ max ↓ min [avg] avg
|
||||
Row(
|
||||
children: [
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Flyme',
|
||||
fontSize: 14,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.red,
|
||||
),
|
||||
@@ -128,16 +132,16 @@ class BatteryInfoPanel extends StatelessWidget {
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
TextSpan(text: '${maxTemp.toStringAsFixed(0)}℃'),
|
||||
TextSpan(text: '${maxTemp.toStringAsFixed(1)}℃'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const SizedBox(width: 6),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Flyme',
|
||||
fontSize: 14,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.blue,
|
||||
),
|
||||
@@ -149,10 +153,22 @@ class BatteryInfoPanel extends StatelessWidget {
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
TextSpan(text: '${minTemp.toStringAsFixed(0)}℃'),
|
||||
TextSpan(text: '${minTemp.toStringAsFixed(1)}℃'),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
_buildIcon('avg', size: 14),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
'${tempAvg.toStringAsFixed(1)}℃',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Flyme',
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -162,24 +178,31 @@ class BatteryInfoPanel extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildIcon(String type) {
|
||||
Widget _buildIcon(String type, {double size = 18}) {
|
||||
switch (type) {
|
||||
case 'voltage':
|
||||
return SvgPicture.asset(
|
||||
'assets/icons/si--lightning-fill.svg',
|
||||
width: 18,
|
||||
height: 18,
|
||||
width: size,
|
||||
height: size,
|
||||
colorFilter: const ColorFilter.mode(Colors.grey, BlendMode.srcIn),
|
||||
);
|
||||
case 'temperature':
|
||||
return SvgPicture.asset(
|
||||
'assets/icons/mdi--temperature.svg',
|
||||
width: 18,
|
||||
height: 18,
|
||||
width: size,
|
||||
height: size,
|
||||
colorFilter: const ColorFilter.mode(Colors.grey, BlendMode.srcIn),
|
||||
);
|
||||
case 'avg': // 🆕
|
||||
return SvgPicture.asset(
|
||||
'assets/icons/avg.svg',
|
||||
width: size,
|
||||
height: size,
|
||||
colorFilter: const ColorFilter.mode(Colors.grey, BlendMode.srcIn),
|
||||
);
|
||||
default:
|
||||
return const Icon(Icons.help_outline, size: 18, color: Colors.grey);
|
||||
return Icon(Icons.help_outline, size: size, color: Colors.grey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user