diff --git a/NiroTelemetrySnapshot.php b/NiroTelemetrySnapshot.php index 86f8b54..5c77e03 100644 --- a/NiroTelemetrySnapshot.php +++ b/NiroTelemetrySnapshot.php @@ -52,8 +52,11 @@ final class NiroTelemetrySnapshot 'ignition' => 'system_root_ign', 'reverse' => 'system_root_reverse', 'parking' => 'system_root_parking', - 'gear' => 'system_individualdrivemode_gear_status', - 'speed' => 'system_individualdrivemode_vehicle_speed', + // The IndividualDriveMode block is a persisted/default structure on + // V038. Its Vehicle Speed and Gear Status stay at 0/P while the car + // is moving. The root fields are the live MICOM callbacks. + 'gear' => 'system_root_gear', + 'speed' => 'system_root_speed', 'previous_speed' => 'system_root_prevspeed', 'parking_brake' => 'system_root_mparkingbrakestatus', 'camera' => 'system_individualdrivemode_fron_rear_camera_status', diff --git a/monitor.php b/monitor.php index 60be40b..ec3c0a5 100644 --- a/monitor.php +++ b/monitor.php @@ -3068,7 +3068,10 @@ $carMonitorSession = car_monitor_launcher_session(); ? (ko ? '후진' : 'Reverse') : (speed !== null && speed > 0 ? (ko ? '주행 중' : 'Driving') : (parking ? t('parked') : (ko ? '정차' : 'Stopped'))); set('telemetry-motion', motion, true); - set('telemetry-gear-speed', `${rawState('gear') ?? '-'} · ${speed ?? '-'} km/h`, value('gear') !== null || speed !== null); + const gear = reverse + ? 'R' + : (parking ? 'P' : (speed !== null && speed > 0 ? 'D' : (ko ? '정차' : 'Stopped'))); + set('telemetry-gear-speed', `${gear} · ${speed ?? '-'} km/h`, speed !== null || value('parking') !== null || value('reverse') !== null); const odometer = numeric('odometer_raw'); set('telemetry-odometer', odometer === null ? null : `${(odometer / 10).toLocaleString(undefined, { minimumFractionDigits: 1, maximumFractionDigits: 1 })} km`); const outside = numeric('outside_temperature'); diff --git a/tests/NiroTelemetrySnapshotTest.php b/tests/NiroTelemetrySnapshotTest.php index 3651bd8..57ab94e 100644 --- a/tests/NiroTelemetrySnapshotTest.php +++ b/tests/NiroTelemetrySnapshotTest.php @@ -25,8 +25,12 @@ $summary = NiroTelemetrySnapshot::summarize([ 'meta_system_dumpsys_ok' => 'true', 'meta_hscan_dumpsys_ok' => 'false', 'system_root_ign' => 'true', - 'system_individualdrivemode_vehicle_speed' => '27', - 'system_individualdrivemode_gear_status' => 'D(0x5)', + 'system_root_speed' => '27', + 'system_root_gear' => '5', + // These persisted/default fields can disagree with the live root values + // and must never drive the dashboard. + 'system_individualdrivemode_vehicle_speed' => '0', + 'system_individualdrivemode_gear_status' => 'P(0x0)', 'system_root_mbatterysoc' => '93', 'hev_micom_hevstatus_mdisplaysoc' => '255', 'hev_micom_hevstatus_odometer' => '2596537', @@ -39,10 +43,10 @@ $summary = NiroTelemetrySnapshot::summarize([ check($summary['available'] === true, 'snapshot is available'); check($summary['online'] === true, 'availability topic is respected'); check($summary['stale'] === false, 'fresh sample is not stale'); -check($summary['metric_count'] === 11, 'metric count excludes sample epoch'); +check($summary['metric_count'] === 13, 'metric count excludes sample epoch'); check($summary['services'] === ['available' => 1, 'total' => 2], 'service health is counted'); check($summary['metrics']['speed']['value'] === '27', 'speed mapping'); -check($summary['metrics']['gear']['value'] === 'D(0x5)', 'gear mapping'); +check($summary['metrics']['gear']['value'] === '5', 'live root gear mapping'); check($summary['metrics']['outside_temperature']['value'] === '25.0', 'climate mapping'); check($summary['metrics']['driver_door']['supported'] === true, 'zero is supported'); check($summary['metrics']['distance_to_empty']['supported'] === false, 'missing value is unsupported');