From 1126fad2c2cb8dca3ae765ca3ca3eb70ffe2a0af Mon Sep 17 00:00:00 2001 From: imbytecat Date: Tue, 12 May 2026 01:09:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(prediction):=20=E4=BD=BF=E7=94=A8=E7=9C=9F?= =?UTF-8?q?=E5=AE=9E=E5=8E=86=E5=8F=B2=E5=AD=97=E6=AE=B5=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E9=A2=84=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/prediction/client.test.ts | 15 ++++++++++ src/server/prediction/client.ts | 43 +++++++--------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/server/prediction/client.test.ts b/src/server/prediction/client.test.ts index 8f0d0b5..d39c9a9 100644 --- a/src/server/prediction/client.test.ts +++ b/src/server/prediction/client.test.ts @@ -74,4 +74,19 @@ describe('prediction client helpers', () => { test('returns null for history-insufficient prediction requests', () => { expect(createPredictionRequest(battery, [battery, battery, battery, battery])).toBeNull() }) + + test('uses only real battery history fields in prediction requests', () => { + const request = createPredictionRequest(battery, [battery, battery, battery, battery, battery]) + const firstHistory = request?.history[0] + + expect(firstHistory).toEqual({ + id: battery.id, + power: battery.power, + power_status: battery.powerStatus, + is_low_power: MYSQL_BOOLEAN.FALSE, + timestamp: battery.createTime, + }) + expect(Object.hasOwn(firstHistory ?? {}, 'charge_capacity_ah')).toBe(false) + expect(Object.hasOwn(firstHistory ?? {}, 'coulombic_efficiency_pct')).toBe(false) + }) }) diff --git a/src/server/prediction/client.ts b/src/server/prediction/client.ts index 26ff2ca..addd90c 100644 --- a/src/server/prediction/client.ts +++ b/src/server/prediction/client.ts @@ -1,12 +1,6 @@ import { LRUCache } from 'lru-cache' import { z } from 'zod' -import { - type BatteryInfo, - type BatteryPrediction, - POWER_STATUS, - type PowerStatus, - toMysqlBoolean, -} from '@/domain/battery' +import { type BatteryInfo, type BatteryPrediction, type PowerStatus, toMysqlBoolean } from '@/domain/battery' import { env } from '@/env' import { getLogger } from '@/server/logger' @@ -26,14 +20,10 @@ export const sohPredictionSchema = z.object({ export type SohPrediction = BatteryPrediction & z.infer type PredictionHistoryItem = { - cycle: number - charge_capacity_ah: number - discharge_capacity_ah: number - charge_energy_wh: number - discharge_energy_wh: number - charge_time: string - discharge_time: string - coulombic_efficiency_pct: number + id: number + power: number + power_status: PowerStatus + is_low_power: string timestamp: string } @@ -78,8 +68,6 @@ const negativeCache = new LRUCache({ }) const inFlightRequests = new Map>() -const round2 = (value: number) => Math.round(value * 100) / 100 - function normalizeMysqlDateTime(value: string) { if (!value.includes('T')) return value @@ -94,23 +82,12 @@ function createCacheKey(battery: BatteryInfo, history: BatteryInfo[]) { return `${battery.mac}:${latestId}:${latestTime}` } -function createHistoryItem(item: BatteryInfo, index: number): PredictionHistoryItem { - const sohRatio = Math.max(0.5, Math.min(1, item.power / 100)) - const chargeCapacity = round2(3.2 * sohRatio) - const efficiency = round2(Math.max(80, Math.min(99, 92 + item.power / 12 - (item.isLowPower ? 4 : 0)))) - const dischargeCapacity = round2(chargeCapacity * (efficiency / 100)) - const chargeEnergy = round2(chargeCapacity * 3.75) - const dischargeEnergy = round2(dischargeCapacity * 3.7) - +function createHistoryItem(item: BatteryInfo): PredictionHistoryItem { return { - cycle: index + 1, - charge_capacity_ah: chargeCapacity, - discharge_capacity_ah: dischargeCapacity, - charge_energy_wh: chargeEnergy, - discharge_energy_wh: dischargeEnergy, - charge_time: item.powerStatus === POWER_STATUS.CHARGING ? '01:20:00' : '01:18:00', - discharge_time: item.isLowPower ? '00:58:00' : '01:10:00', - coulombic_efficiency_pct: efficiency, + id: item.id, + power: item.power, + power_status: item.powerStatus, + is_low_power: toMysqlBoolean(item.isLowPower), timestamp: normalizeMysqlDateTime(item.createTime), } }