feat(dev): 배터리 부하 테스트 실측을 CSV 로 남긴다

50시간짜리 소모율 측정을 걸려고 보니 기록이 분석에 못 쓸 상태였다.

1) 테스트가 10초마다 굴리는 mbb? 의 응답(rbb)에 **전압·온도가 로그에 안 남았다.**
   파싱은 해서 화면에는 띄우면서 파일에는 "full measurement header (battery+IMU+temp)"
   라는 고정 문자열만 썼다. 즉 이 테스트의 유일한 10초 주기 표본이 파일에 없었다.
   (30초 주기 rsn 만 전압을 남기고 있었다.)

2) 진행 중 기록이 없었다. 시작·정지 두 줄뿐이라, 50시간을 걸어 놓고 중간에 프로세스가
   죽으면 정지 줄조차 안 남는다 — 어디까지가 유효한 구간인지 판별할 방법이 없다.

3) BLE 로그는 초당 수 줄이 섞여 들어간다(RSSI 가 68%를 차지). 50시간이면 수십만 줄에서
   전압만 골라내야 한다.

그래서 소모율 분석에 필요한 것만 별도 CSV 로 남긴다:
  Download/VesiScan_BattDrain_<시작시각>.csv
  time,elapsed_s,source,batt_mv,temp_c,connected,imu_*,full_*

10초 주기면 50시간에 18,000행이라 그대로 스프레드시트에 올라간다. 줄마다 flush 하므로
앱이 죽어도 그 시점까지는 남는다.

**rbb 가 안 와도 1분마다 한 행(source=tick)을 남긴다.** 프로브가 죽거나 BLE 가 끊기면
rbb 가 멈추는데 그때 CSV 도 같이 멈추면 "언제 끊겼는지"를 파일만 보고는 알 수 없다.
같은 주기로 BLE 로그에도 요약 한 줄을 남겨 두 파일을 맞춰 볼 수 있게 했다.

다이얼로그에 기록 파일명을 띄운다 — 장시간 돌린 뒤 Downloads 에서 어느 파일을 꺼내야
하는지 화면에서 바로 알아야 하고, 생성 실패도 여기서 보인다.

실기기 검증(23021RAA2Y · VBT26080001 · 141초): CSV 생성 · rbb 행 14건(전압 3849~3854mV,
온도 24.3~24.4C) · 60초 tick 1건 · stop 행 · BLE 로그의 rbb 줄에 값 표시 확인.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 09:30:54 +09:00
parent 2e9b9b204c
commit cc950184cd
3 changed files with 131 additions and 2 deletions
@@ -1833,7 +1833,16 @@ class BleManager private constructor(private val context: Context) {
debugLogger.rx("rls", data.size, "led_state=$state")
}
"rbb:" -> {
debugLogger.rx("rbb", data.size, "full measurement header (battery+IMU+temp)")
// 값을 함께 남긴다 — 이 응답이 배터리 소모 실측의 유일한 10초 주기 표본인데
// 예전에는 고정 문자열만 남아 파일만 보고는 전압 추이를 전혀 알 수 없었다.
// batt 는 첫 필드라 offset 4, temp 는 CRC 직전이라 size-4 (BatteryDrainTester 와 동일 규약).
val detail = if (data.size >= 12) {
val mv = ((data[4].toInt() and 0xFF) shl 8) or (data[5].toInt() and 0xFF)
val t = (((data[data.size - 4].toInt() and 0xFF) shl 8) or
(data[data.size - 3].toInt() and 0xFF)) / 100f
"battery=${mv}mV" + if (t in 0f..80f) " temp=%.2fC".format(t) else ""
} else "full measurement header (battery+IMU+temp)"
debugLogger.rx("rbb", data.size, detail)
onMbbHeaderReceived?.invoke(data)
piezoCollector.addPacket(data)
}