141 lines
3.9 KiB
Dart
141 lines
3.9 KiB
Dart
import 'dart:developer' as dev;
|
|
import '../utils/time_utils.dart';
|
|
|
|
/// 充电日志解析器
|
|
class ChargeParser {
|
|
/// 解析充电数据,返回解析结果
|
|
static ParseResult parse(List<String> lines, DateTime? chargingStartTime) {
|
|
dev.log('[ChargeParser] 开始解析,共 ${lines.length} 行', name: 'BatteryHealth');
|
|
|
|
final validLines = _collectValidLines(lines, chargingStartTime);
|
|
if (validLines.isEmpty) {
|
|
dev.log('[ChargeParser] 无有效时间窗口内的数据行', name: 'BatteryHealth');
|
|
return ParseResult.empty();
|
|
}
|
|
|
|
// 按时间戳从新到旧排序
|
|
validLines.sort((a, b) => b['timestamp'].compareTo(a['timestamp']));
|
|
final latest = validLines.first;
|
|
final latestLine = latest['line'] as String;
|
|
final latestType = latest['type'] as String;
|
|
|
|
dev.log(
|
|
'[ChargeParser] 最新有效数据: $latestType, 时间: ${latest['timestamp']}',
|
|
name: 'BatteryHealth',
|
|
);
|
|
|
|
if (latestType == 'wls') {
|
|
return _parseWireless(latestLine);
|
|
} else {
|
|
return _parseWired(latestLine);
|
|
}
|
|
}
|
|
|
|
static List<Map<String, dynamic>> _collectValidLines(
|
|
List<String> lines,
|
|
DateTime? chargingStartTime,
|
|
) {
|
|
final result = <Map<String, dynamic>>[];
|
|
for (String line in lines) {
|
|
final timestamp = TimeUtils.parseLogTimestamp(line);
|
|
if (!TimeUtils.isLogTimestampValid(timestamp, chargingStartTime)) {
|
|
continue;
|
|
}
|
|
|
|
final isUsb =
|
|
line.contains('chg_usb') &&
|
|
(line.contains('ibus=') || line.contains('real_type='));
|
|
final isWls = line.contains('chg_wls') && line.contains('wls_online=1');
|
|
|
|
if (isUsb || isWls) {
|
|
result.add({
|
|
'line': line,
|
|
'timestamp': timestamp,
|
|
'type': isWls ? 'wls' : 'usb',
|
|
});
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static ParseResult _parseWireless(String line) {
|
|
final typeReg = RegExp(r'wls_type=(\w+)');
|
|
final voltReg = RegExp(r'wls_volt=(\d+)');
|
|
final currReg = RegExp(r'wls_curr=(\d+)');
|
|
|
|
final wlsType = typeReg.firstMatch(line)?.group(1);
|
|
final volt = int.parse(voltReg.firstMatch(line)?.group(1) ?? '0');
|
|
final curr = int.parse(currReg.firstMatch(line)?.group(1) ?? '0');
|
|
|
|
return ParseResult(
|
|
isWireless: true,
|
|
chargeType: wlsType ?? '无线',
|
|
power: (volt * curr) / 1000000.0,
|
|
volt: volt / 1000.0,
|
|
curr: curr / 1000.0,
|
|
wiredLevel: null,
|
|
);
|
|
}
|
|
|
|
static ParseResult _parseWired(String line) {
|
|
final ibusReg = RegExp(r'ibus=(\d+)');
|
|
final vbusReg = RegExp(r'vbus=(\d+)');
|
|
final levelReg = RegExp(r'wired_level=(\d+)');
|
|
final typeReg = RegExp(r'real_type=(\w+)');
|
|
|
|
final ibus = int.parse(ibusReg.firstMatch(line)?.group(1) ?? '0');
|
|
final vbus = int.parse(vbusReg.firstMatch(line)?.group(1) ?? '0');
|
|
final realType = typeReg.firstMatch(line)?.group(1);
|
|
final level = int.parse(levelReg.firstMatch(line)?.group(1) ?? '0');
|
|
|
|
String chargeType;
|
|
if (realType == 'PPS') {
|
|
chargeType = 'PPS';
|
|
} else if (realType == 'SDP' || realType == 'FLOAT') {
|
|
chargeType = 'SDP';
|
|
} else if (level >= 3) {
|
|
chargeType = 'PPS';
|
|
} else {
|
|
chargeType = 'SDP';
|
|
}
|
|
|
|
return ParseResult(
|
|
isWireless: false,
|
|
chargeType: chargeType,
|
|
power: (vbus * ibus) / 1000000000000.0,
|
|
volt: vbus / 1000000.0,
|
|
curr: ibus / 1000000.0,
|
|
wiredLevel: chargeType == 'PPS' ? level : null,
|
|
);
|
|
}
|
|
}
|
|
|
|
class ParseResult {
|
|
final bool isWireless;
|
|
final String chargeType;
|
|
final double power;
|
|
final double volt;
|
|
final double curr;
|
|
final int? wiredLevel;
|
|
|
|
ParseResult({
|
|
required this.isWireless,
|
|
required this.chargeType,
|
|
required this.power,
|
|
required this.volt,
|
|
required this.curr,
|
|
this.wiredLevel,
|
|
});
|
|
|
|
factory ParseResult.empty() {
|
|
return ParseResult(
|
|
isWireless: false,
|
|
chargeType: '',
|
|
power: 0.0,
|
|
volt: 0.0,
|
|
curr: 0.0,
|
|
wiredLevel: null,
|
|
);
|
|
}
|
|
}
|