Skip to content

Commit bbdb2d8

Browse files
committed
feat(chargepilot): warn on low charge limit
1 parent ae24c99 commit bbdb2d8

5 files changed

Lines changed: 71 additions & 1 deletion

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.evsuite.chargepilot
2+
3+
/** Read-only warning when a planned charging stop cannot reach its assumed departure charge. */
4+
internal data class ChargeLimitAdvice(
5+
val limitPercent: Int,
6+
val departurePercent: Double,
7+
) {
8+
companion object {
9+
fun of(
10+
usesDepartureCharge: Boolean,
11+
departurePercent: Double,
12+
limitPercent: Int?,
13+
): ChargeLimitAdvice? {
14+
if (!usesDepartureCharge) return null
15+
val limit = limitPercent?.takeIf { it in 0..100 } ?: return null
16+
if (!departurePercent.isFinite() || departurePercent !in 0.0..100.0) return null
17+
if (departurePercent <= limit.toDouble()) return null
18+
return ChargeLimitAdvice(limit, departurePercent)
19+
}
20+
}
21+
}

‎app/src/main/java/com/evsuite/chargepilot/ChargeStopActivity.kt‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.evsuite.chargepilot.route.RoutingCredentials
2121
import com.evsuite.chargepilot.route.RoutingTransport
2222
import com.evsuite.hardware.FirmwareInfo
2323
import com.evsuite.hardware.saic.NavigationHandoff
24+
import com.evsuite.hardware.saic.SaicCharging
2425
import com.evsuite.hardware.saic.SaicNav
2526
import com.evsuite.hardware.saic.SaicNavGuidance
2627
import com.evsuite.hardware.telemetry.ChargeStopPlan
@@ -467,13 +468,15 @@ class ChargeStopActivity : AppCompatActivity() {
467468
}
468469
"$body | second road=${alternative?.viaLabel ?: "none"}"
469470
}
471+
val chargeLimitPercent = SaicCharging.chargeLimitPercent()
470472
runOnUiThread {
471473
if (isFinishing || isDestroyed) return@runOnUiThread
472474
render(
473475
place, route, chain, effective, chargers, grade, whatIf, alternative,
474476
motorwayFree,
475477
(if (retried) 2 else 1) + (if (motorwayFree == null) 0 else 1),
476478
settings.departurePercent,
479+
chargeLimitPercent,
477480
)
478481
announce(
479482
when {
@@ -626,6 +629,7 @@ class ChargeStopActivity : AppCompatActivity() {
626629
motorwayFree: MotorwayFree?,
627630
routeRequests: Int,
628631
departurePercent: Double,
632+
chargeLimitPercent: Int?,
629633
) {
630634
val plan = chain?.legs?.firstOrNull()?.plan
631635
val charger = chargers.firstOrNull()
@@ -662,7 +666,19 @@ class ChargeStopActivity : AppCompatActivity() {
662666
format(it.uncertaintyPercent, "%.1f"),
663667
)
664668
}
665-
binding.chargeStopDetail.text = listOfNotNull(detail, gradeLine).joinToString("\n")
669+
val chargeLimitLine = ChargeLimitAdvice.of(
670+
usesDepartureCharge = chain.stops.isNotEmpty(),
671+
departurePercent = departurePercent,
672+
limitPercent = chargeLimitPercent,
673+
)?.let {
674+
getString(
675+
R.string.charge_stop_limit_advice,
676+
it.limitPercent,
677+
format(it.departurePercent, "%.0f"),
678+
)
679+
}
680+
binding.chargeStopDetail.text =
681+
listOfNotNull(chargeLimitLine, detail, gradeLine).joinToString("\n")
666682

667683
renderCharger(plan, chargers)
668684
renderWhatIf(whatIf, alternative)

‎app/src/main/res/values-fr/strings.xml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ Cette charge atteint environ %4$s à ce rythme</string>
274274
<string name="charge_stop_no_position">Aucune position. Le récepteur de la voiture a été interrogé et n’a rien répondu. Réessayez à ciel dégagé.</string>
275275
<string name="charge_stop_plan_none">Aucun arrêt nécessaire · environ %1$s %% à l’arrivée, %2$s %% au-dessus de la réserve</string>
276276
<string name="charge_stop_plan_stop">Recharger après environ %1$s km (± %2$s km)</string>
277+
<string name="charge_stop_limit_advice">La limite de charge du véhicule est de %1$d %%, mais ce trajet prévoit de repartir d’un arrêt à %2$s %%. Relevez la limite dans le véhicule avant de recharger.</string>
277278
<string name="charge_stop_refused_charge">La charge est illisible : rien ne peut être planifié.</string>
278279
<string name="charge_stop_refused_route">Aucune longueur d’itinéraire sur laquelle planifier.</string>
279280
<string name="charge_stop_refused_rate">Pas encore de taux exploitable. Enregistrez quelques trajets et ceci se remplira.</string>

‎app/src/main/res/values/strings.xml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ This charge reaches about %4$s at that rate</string>
278278
<string name="charge_stop_no_position">No position. The car\u2019s receiver was asked and answered nothing. Try again where the sky is clear.</string>
279279
<string name="charge_stop_plan_none">No stop needed · about %1$s %% left on arrival, %2$s %% above the reserve</string>
280280
<string name="charge_stop_plan_stop">Charge after about %1$s km (± %2$s km)</string>
281+
<string name="charge_stop_limit_advice">Vehicle charge limit is %1$d %%, but this plan assumes leaving a charging stop at %2$s %%. Raise the limit in the vehicle before charging.</string>
281282
<string name="charge_stop_refused_charge">Charge is unreadable, so there is nothing to plan from.</string>
282283
<string name="charge_stop_refused_route">No route length to plan against.</string>
283284
<string name="charge_stop_refused_rate">No usable rate yet. Record a few trips and this fills in.</string>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.evsuite.chargepilot
2+
3+
import org.junit.Assert.assertEquals
4+
import org.junit.Assert.assertNull
5+
import org.junit.Test
6+
7+
class ChargeLimitAdviceTest {
8+
@Test
9+
fun `plan warns when charging stop departure exceeds vehicle limit`() {
10+
assertEquals(
11+
ChargeLimitAdvice(limitPercent = 80, departurePercent = 92.0),
12+
ChargeLimitAdvice.of(
13+
usesDepartureCharge = true,
14+
departurePercent = 92.0,
15+
limitPercent = 80,
16+
),
17+
)
18+
}
19+
20+
@Test
21+
fun `sufficient or unreadable limit stays silent`() {
22+
assertNull(ChargeLimitAdvice.of(true, departurePercent = 80.0, limitPercent = 80))
23+
assertNull(ChargeLimitAdvice.of(true, departurePercent = 80.0, limitPercent = 90))
24+
assertNull(ChargeLimitAdvice.of(true, departurePercent = 92.0, limitPercent = null))
25+
}
26+
27+
@Test
28+
fun `plan without charging stop does not claim departure target is needed`() {
29+
assertNull(ChargeLimitAdvice.of(false, departurePercent = 92.0, limitPercent = 80))
30+
}
31+
}

0 commit comments

Comments
 (0)