Add readable charging curve and SOC power table

This commit is contained in:
TCFDONMEZ
2026-09-30 11:30:13 +03:00
parent 76d1d680d6
commit 48a210db9b
5 changed files with 30 additions and 11 deletions
+1
View File
@@ -0,0 +1 @@
db95c341f6b975d9b4b9dceea79adb0b3829a0bafe8a86ea31d5b7e4012206b0 FatihsMG4-unstable-2.2.22.apk
+2 -2
View File
@@ -34,8 +34,8 @@ android {
applicationId "com.evsuite.abrp" applicationId "com.evsuite.abrp"
minSdk 27 minSdk 27
targetSdk 36 targetSdk 36
versionCode 38 versionCode 39
versionName "2.2.21" versionName "2.2.22"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -7,23 +7,36 @@ import android.util.AttributeSet;
import android.view.View; import android.view.View;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale;
/** Lightweight SOC/power charging curve, avoiding a heavy chart dependency on AAOS 9. */ /** Lightweight SOC/power charging curve, avoiding a heavy chart dependency on AAOS 9. */
public final class ChargingGraphView extends View { public final class ChargingGraphView extends View {
private final Paint grid = new Paint(1), line = new Paint(1), text = new Paint(1); private final Paint grid = new Paint(1), line = new Paint(1), text = new Paint(1);
private final List<float[]> points = new ArrayList<>(); private final List<float[]> points = new ArrayList<>();
public ChargingGraphView(Context c, AttributeSet a) { super(c,a); grid.setColor(0x3348C7D9); line.setColor(0xFFFFC857); line.setStrokeWidth(4); text.setColor(0xFFBDC4C6); text.setTextSize(24); } private final float[] socPower = new float[101];
public ChargingGraphView(Context c, AttributeSet a) { super(c,a); java.util.Arrays.fill(socPower, Float.NaN); grid.setColor(0x5548C7D9); line.setColor(0xFFFFC857); line.setStrokeWidth(4); text.setColor(0xFFBDC4C6); text.setTextSize(20); }
synchronized void add(Float soc, Float power) { synchronized void add(Float soc, Float power) {
if (soc == null || power == null || power >= 0) return; if (soc == null || power == null || power >= 0) return;
float p = Math.abs(power); float p = Math.abs(power);
if (!points.isEmpty() && Math.abs(points.get(points.size()-1)[0] - soc) < .1f) points.remove(points.size()-1); if (!points.isEmpty() && Math.abs(points.get(points.size()-1)[0] - soc) < .1f) points.remove(points.size()-1);
points.add(new float[]{soc,p}); if (points.size() > 500) points.remove(0); invalidate(); points.add(new float[]{soc,p}); if (points.size() > 500) points.remove(0);
socPower[Math.max(0, Math.min(100, Math.round(soc)))] = p; invalidate();
}
synchronized String tableText() {
StringBuilder out = new StringBuilder("SOC Şarj gücü\n");
boolean found = false;
for (int soc=0; soc<=100; soc++) if (!Float.isNaN(socPower[soc])) {
found = true;
out.append(String.format(Locale.getDefault(), "%3d %% %6.1f kW\n", soc, socPower[soc]));
}
return found ? out.toString().trim() : "Henüz şarj ölçümü yok";
} }
@Override protected synchronized void onDraw(Canvas c) { @Override protected synchronized void onDraw(Canvas c) {
super.onDraw(c); float w=getWidth(), h=getHeight()-34; super.onDraw(c); float left=58, right=getWidth()-12, top=12, bottom=getHeight()-38;
for(int i=0;i<=4;i++) c.drawLine(0,h*i/4,w,h*i/4,grid); float max=20; for(float[] p:points) max=Math.max(max,p[1]); max=(float)Math.ceil(max/20f)*20f;
c.drawText("SOC % → Şarj gücü (kW)",12,getHeight()-5,text); for(int i=0;i<=5;i++){float y=bottom-(bottom-top)*i/5f; c.drawLine(left,y,right,y,grid); c.drawText(String.format(Locale.US,"%.0f",max*i/5f),4,y+7,text);}
float max=20; for(float[] p:points) max=Math.max(max,p[1]); for(int soc=0;soc<=100;soc+=20){float x=left+(right-left)*soc/100f; c.drawLine(x,top,x,bottom,grid); c.drawText(String.valueOf(soc),x-10,getHeight()-8,text);}
for(int i=1;i<points.size();i++){float[] a=points.get(i-1),b=points.get(i); c.drawLine(a[0]*w/100,h-a[1]*h/max,b[0]*w/100,h-b[1]*h/max,line);} c.drawText("kW",5,20,text); c.drawText("SOC %",right-52,getHeight()-8,text);
for(int i=1;i<points.size();i++){float[] a=points.get(i-1),b=points.get(i); float ax=left+a[0]*(right-left)/100, ay=bottom-a[1]*(bottom-top)/max, bx=left+b[0]*(right-left)/100, by=bottom-b[1]*(bottom-top)/max; c.drawLine(ax,ay,bx,by,line); c.drawCircle(bx,by,4,line);}
} }
} }
@@ -113,7 +113,7 @@ public class MainActivity extends AppCompatActivity {
consumptionSpeed, consumptionTime, consumptionSoc; consumptionSpeed, consumptionTime, consumptionSoc;
private Button consumptionReset; private Button consumptionReset;
private TextView chargeStatus, chargeSoc, chargeVoltage, chargeCurrent, chargePower, private TextView chargeStatus, chargeSoc, chargeVoltage, chargeCurrent, chargePower,
chargeEnergy, chargeDuration; chargeEnergy, chargeDuration, chargeCurveTable;
private ChargingGraphView chargeGraph; private ChargingGraphView chargeGraph;
private long chargeStartMs, lastChargeMs; private long chargeStartMs, lastChargeMs;
private double chargedKwh; private double chargedKwh;
@@ -883,6 +883,7 @@ public class MainActivity extends AppCompatActivity {
chargeEnergy = chargingPane.findViewById(R.id.charge_energy); chargeEnergy = chargingPane.findViewById(R.id.charge_energy);
chargeDuration = chargingPane.findViewById(R.id.charge_duration); chargeDuration = chargingPane.findViewById(R.id.charge_duration);
chargeGraph = chargingPane.findViewById(R.id.charge_graph); chargeGraph = chargingPane.findViewById(R.id.charge_graph);
chargeCurveTable = chargingPane.findViewById(R.id.charge_curve_table);
} }
private void refreshCharging(EnergySnapshot s) { private void refreshCharging(EnergySnapshot s) {
@@ -905,7 +906,10 @@ public class MainActivity extends AppCompatActivity {
chargeEnergy.setText(charging ? String.format(java.util.Locale.getDefault(), "%.2f kWh", chargedKwh) : "—"); chargeEnergy.setText(charging ? String.format(java.util.Locale.getDefault(), "%.2f kWh", chargedKwh) : "—");
long sec = chargeStartMs == 0 ? 0 : (now-chargeStartMs)/1000; long sec = chargeStartMs == 0 ? 0 : (now-chargeStartMs)/1000;
chargeDuration.setText(charging ? String.format(java.util.Locale.getDefault(), "%02d:%02d:%02d", sec/3600,(sec%3600)/60,sec%60) : "—"); chargeDuration.setText(charging ? String.format(java.util.Locale.getDefault(), "%02d:%02d:%02d", sec/3600,(sec%3600)/60,sec%60) : "—");
if (charging) chargeGraph.add(s.getSocPercent(), s.getBatteryPowerKw()); if (charging) {
chargeGraph.add(s.getSocPercent(), s.getBatteryPowerKw());
chargeCurveTable.setText(chargeGraph.tableText());
}
} }
private void refreshConsumption() { private void refreshConsumption() {
@@ -15,6 +15,7 @@
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp" android:layout_marginTop="16dp" android:background="@drawable/bg_glass"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="20dp" android:layout_marginTop="16dp" android:background="@drawable/bg_glass">
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="ŞARJ EĞRİSİ" android:textAppearance="@style/Text.EV.Eyebrow"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="ŞARJ EĞRİSİ" android:textAppearance="@style/Text.EV.Eyebrow"/>
<com.evsuite.abrp.ChargingGraphView android:id="@+id/charge_graph" android:layout_width="match_parent" android:layout_height="280dp" android:layout_marginTop="12dp"/> <com.evsuite.abrp.ChargingGraphView android:id="@+id/charge_graph" android:layout_width="match_parent" android:layout_height="280dp" android:layout_marginTop="12dp"/>
<TextView android:id="@+id/charge_curve_table" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:fontFamily="monospace" android:text="Henüz şarj ölçümü yok" android:textAppearance="@style/Text.EV.Body" android:textColor="@color/ev_cyan"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>