Count driving only and include charging losses
This commit is contained in:
@@ -24,6 +24,8 @@ import java.util.UUID;
|
||||
* reading the database needs to place it on a timeline — but nothing is measured from them.
|
||||
*/
|
||||
final class ChargeSessionTracker {
|
||||
static final double CHARGING_LOSS_PERCENT = 10d;
|
||||
static final double GRID_ENERGY_FACTOR = 1d + CHARGING_LOSS_PERCENT / 100d;
|
||||
private static final String PREFS = "charging_sessions_v1";
|
||||
private static final String ACTIVE = "active";
|
||||
private static final String LAST = "last_completed";
|
||||
@@ -67,6 +69,7 @@ final class ChargeSessionTracker {
|
||||
final Float startSocPercent;
|
||||
final Float currentSocPercent;
|
||||
final double energyKwh;
|
||||
final double gridEnergyKwh;
|
||||
final double pricePerKwh;
|
||||
final double totalCost;
|
||||
final List<Point> points;
|
||||
@@ -80,8 +83,9 @@ final class ChargeSessionTracker {
|
||||
this.startSocPercent = startSocPercent;
|
||||
this.currentSocPercent = currentSocPercent;
|
||||
this.energyKwh = energyKwh;
|
||||
this.gridEnergyKwh = gridEnergyKwh(energyKwh);
|
||||
this.pricePerKwh = pricePerKwh;
|
||||
this.totalCost = energyKwh * pricePerKwh;
|
||||
this.totalCost = totalCost(energyKwh, pricePerKwh);
|
||||
this.points = points;
|
||||
}
|
||||
}
|
||||
@@ -140,6 +144,14 @@ final class ChargeSessionTracker {
|
||||
return Double.longBitsToDouble(prefs.getLong(PRICE, 0L));
|
||||
}
|
||||
|
||||
static double gridEnergyKwh(double batteryEnergyKwh) {
|
||||
return batteryEnergyKwh * GRID_ENERGY_FACTOR;
|
||||
}
|
||||
|
||||
static double totalCost(double batteryEnergyKwh, double pricePerKwh) {
|
||||
return gridEnergyKwh(batteryEnergyKwh) * pricePerKwh;
|
||||
}
|
||||
|
||||
synchronized List<JSONObject> pendingUploads() {
|
||||
JSONArray array = pendingArray();
|
||||
List<JSONObject> result = new ArrayList<>();
|
||||
@@ -264,8 +276,12 @@ final class ChargeSessionTracker {
|
||||
}
|
||||
JSONObject json = new JSONObject().put("sessionId", id).put("startedAt", startedAtMs)
|
||||
.put("endedAt", endedAtMs).put("durationSeconds", activeSeconds())
|
||||
.put("energyKwh", energyKwh).put("pricePerKwh", pricePerKwh)
|
||||
.put("totalCost", energyKwh * pricePerKwh).put("curve", curve)
|
||||
.put("energyKwh", energyKwh)
|
||||
.put("chargingLossPercent", CHARGING_LOSS_PERCENT)
|
||||
.put("gridEnergyKwh", gridEnergyKwh(energyKwh))
|
||||
.put("pricePerKwh", pricePerKwh)
|
||||
.put("totalCost", totalCost(energyKwh, pricePerKwh))
|
||||
.put("curve", curve)
|
||||
.put("meteredSeconds", meteredSeconds)
|
||||
.put("curveIntervalMs", curveIntervalMs);
|
||||
if (startSoc != null) json.put("startSocPercent", startSoc);
|
||||
|
||||
@@ -10,7 +10,9 @@ package com.evsuite.abrp;
|
||||
* or a regeneration-discarding gross fallback. Three sources, three answers, none of them
|
||||
* agreeing with the car's dashboard — the counters were not measuring the same quantity.
|
||||
*
|
||||
* What the vehicle reports is net DC battery power: positive out of the pack, negative in.
|
||||
* Only moving intervals belong to these driving counters. Parked HVAC/accessory use is
|
||||
* deliberately excluded from distance, energy, time and SOC-drop totals. What the vehicle
|
||||
* reports while moving is net DC battery power: positive out of the pack, negative in.
|
||||
* Integrating it as-is means regeneration subtracts, which is exactly what the car's own
|
||||
* kWh figure does. Discarding the negative half (the old {@code max(0, kW)} fallback) is
|
||||
* what made our number read high.
|
||||
@@ -69,24 +71,19 @@ final class ConsumptionMath {
|
||||
: (previousSpeedKmh != null ? Math.abs(previousSpeedKmh) : 0f);
|
||||
float previous = previousSpeedKmh != null ? Math.abs(previousSpeedKmh) : current;
|
||||
float effectiveKmh = (previous + current) * 0.5f;
|
||||
if (effectiveKmh < SPEED_DEAD_BAND_KMH) effectiveKmh = 0f;
|
||||
else if (effectiveKmh > 90f) effectiveKmh *= 1.0035f;
|
||||
if (effectiveKmh < SPEED_DEAD_BAND_KMH) {
|
||||
return new Step(0d, 0d, 0d, 0d);
|
||||
} else if (effectiveKmh > 90f) effectiveKmh *= 1.0035f;
|
||||
else if (effectiveKmh > 30f) effectiveKmh *= 1.0015f;
|
||||
double km = effectiveKmh * hours;
|
||||
|
||||
// Energy: trapezoidal net DC power, regeneration included with its own sign.
|
||||
double kwh = 0d;
|
||||
if (powerKw != null && Math.abs(powerKw) <= MAX_PLAUSIBLE_KW) {
|
||||
if (current == 0f && powerKw < 0f) {
|
||||
// Standing still with power flowing in is charging or pre-conditioning
|
||||
// recovery, not a drive crediting itself energy it never spent.
|
||||
kwh = 0d;
|
||||
} else {
|
||||
double effectiveKw = previousPowerKw != null && Math.abs(previousPowerKw) <= MAX_PLAUSIBLE_KW
|
||||
? (previousPowerKw + powerKw) * 0.5d
|
||||
: powerKw;
|
||||
kwh = effectiveKw * hours;
|
||||
}
|
||||
double effectiveKw = previousPowerKw != null && Math.abs(previousPowerKw) <= MAX_PLAUSIBLE_KW
|
||||
? (previousPowerKw + powerKw) * 0.5d
|
||||
: powerKw;
|
||||
kwh = effectiveKw * hours;
|
||||
}
|
||||
|
||||
double socDrop = (!charging && previousSocPercent != null && socPercent != null)
|
||||
|
||||
@@ -119,7 +119,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
private TextInputEditText consumptionSohInput;
|
||||
private java.time.LocalDate selectedConsumptionDate = java.time.LocalDate.now();
|
||||
private TextView chargeStatus, chargeSoc, chargeStartSoc, chargeVoltage, chargeCurrent, chargePower,
|
||||
chargeEnergy, chargeDuration, chargeTotalCost, chargeCurveTable;
|
||||
chargeEnergy, chargeGridEnergy, chargeDuration, chargeTotalCost, chargeCurveTable;
|
||||
private TextInputLayout chargePriceLayout;
|
||||
private TextInputEditText chargePriceInput;
|
||||
private ChargeSessionTracker chargeSessionTracker;
|
||||
@@ -936,6 +936,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
chargeCurrent = chargingPane.findViewById(R.id.charge_current);
|
||||
chargePower = chargingPane.findViewById(R.id.charge_power);
|
||||
chargeEnergy = chargingPane.findViewById(R.id.charge_energy);
|
||||
chargeGridEnergy = chargingPane.findViewById(R.id.charge_grid_energy);
|
||||
chargeDuration = chargingPane.findViewById(R.id.charge_duration);
|
||||
chargeTotalCost = chargingPane.findViewById(R.id.charge_total_cost);
|
||||
chargeGraph = chargingPane.findViewById(R.id.charge_graph);
|
||||
@@ -980,6 +981,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
chargeCurrent.setText(fmt(s.getBatteryCurrentA(), "%.1f A"));
|
||||
chargePower.setText(s.getBatteryPowerKw() == null ? "—" : String.format(java.util.Locale.getDefault(), "%.1f kW", Math.abs(s.getBatteryPowerKw())));
|
||||
chargeEnergy.setText(session.startedAtMs > 0 ? String.format(java.util.Locale.getDefault(), "%.2f kWh", session.energyKwh) : "—");
|
||||
chargeGridEnergy.setText(session.startedAtMs > 0 ? String.format(
|
||||
java.util.Locale.getDefault(), "%.2f kWh", session.gridEnergyKwh) : "—");
|
||||
long sec = session.durationSeconds;
|
||||
chargeDuration.setText(session.startedAtMs > 0 ? String.format(java.util.Locale.getDefault(), "%02d:%02d:%02d", sec/3600,(sec%3600)/60,sec%60) : "—");
|
||||
chargeTotalCost.setText(session.startedAtMs > 0 ? String.format(java.util.Locale.getDefault(), "%.2f ₺", session.totalCost) : "—");
|
||||
|
||||
Reference in New Issue
Block a user