fix(charging): validate status and budget phase detection
Tests / test (push) Waiting to run

Do not latch full on transient zero current; require explicit completion. Validate go-e errors and Pico status/timestamps, keep historical events diagnostic, and preserve faults until a fresh successful poll. Budget the 6 A phase probe through the manager and correct stale phase counts conservatively.

Add adapter, regulator, isolated runtime and Symcon regression cases plus migration documentation. Verified: composer check (402 tests, 1875 assertions), 92 pure-function assertions in Symcon 8.0, git diff --check. No plant deployment or hardware commands.
This commit is contained in:
dh
2026-10-07 18:24:47 +00:00
parent 372b997876
commit 5885681669
10 changed files with 836 additions and 98 deletions
+53 -7
View File
@@ -71,7 +71,7 @@ final class LadestationReglerTest extends TestCase
], false);
self::assertSame(LadestationRegler::PHASEN_UNBEKANNT, $status['Phasenzahl']);
self::assertSame([0], LadestationRegler::leistungsangebot(
self::assertSame([0, 4104], LadestationRegler::leistungsangebot(
true,
true,
true,
@@ -94,15 +94,15 @@ final class LadestationReglerTest extends TestCase
self::assertSame(2, $status['Fahrzeugstatus']);
}
public function testGeladenWirdErstNachZuvorGemessenerLadeleistungErkannt(): void
public function testNiedrigstromNachLadungIstKeinBestaetigtesLadeende(): void
{
$status = LadestationRegler::normalisiereStatus([
'Rohstatus' => 2,
'Istleistung_W' => 0.0,
], true, false, true, true);
self::assertTrue($status['FahrzeugGeladen']);
self::assertSame(4, $status['Fahrzeugstatus']);
self::assertFalse($status['FahrzeugGeladen']);
self::assertSame(2, $status['Fahrzeugstatus']);
}
public function testAbsichtlichGestoppteLadungWirdNichtAlsGeladenErkannt(): void
@@ -116,15 +116,61 @@ final class LadestationReglerTest extends TestCase
self::assertSame(2, $status['Fahrzeugstatus']);
}
public function testErkanntesLadeendeBleibtBisZumAbsteckenErhalten(): void
public function testAltesLadeendeOhneAktuelleBestaetigungWirdVerworfen(): void
{
$status = LadestationRegler::normalisiereStatus([
'Rohstatus' => 2,
'Istleistung_W' => 0.0,
], true, true, false);
self::assertTrue($status['FahrzeugGeladen']);
self::assertSame(4, $status['Fahrzeugstatus']);
self::assertFalse($status['FahrzeugGeladen']);
self::assertSame(2, $status['Fahrzeugstatus']);
}
public function testExplizitesLadeendeWirdBeiErneuterLadungZurueckgenommen(): void
{
$ende = ['Rohstatus' => 4, 'Istleistung_W' => 0.0, 'LadeendeBestaetigt' => true];
self::assertTrue(LadestationRegler::normalisiereStatus($ende, true)['FahrzeugGeladen']);
$ende['Istleistung_W'] = 1380.0;
self::assertFalse(LadestationRegler::normalisiereStatus($ende, true, true)['FahrzeugGeladen']);
$ende['Rohstatus'] = 1;
$ende['Istleistung_W'] = 0.0;
self::assertFalse(LadestationRegler::normalisiereStatus($ende, true, true)['FahrzeugGeladen']);
}
public function testFrischePhasenmessungKorrigiertGespeicherteEinphasigkeit(): void
{
$status = LadestationRegler::normalisiereStatus([
'Rohstatus' => 2, 'Istleistung_W' => 4104.0, 'Iststrom_A' => 6.0, 'Phasenzahl' => 3,
], true, false, true, true, 1);
self::assertSame(3, $status['Phasenzahl']);
}
public function testNullUndSchwacheLeistungBeweisenKeinePhase(): void
{
foreach ([0.0, 100.0, 800.0, 1264.0] as $leistung) {
self::assertSame(0, LadestationRegler::erkennePhasenzahlAusLeistung($leistung, 6));
}
}
public function testEinzelneAktivePhaseVerkleinertKeinBestaetigtesDreiphasenbudget(): void
{
$rohstatus = ['Rohstatus' => 2, 'Istleistung_W' => 1380.0, 'Phasenzahl' => 1];
self::assertSame(3, LadestationRegler::normalisiereStatus($rohstatus, true, false, true, true, 3)['Phasenzahl']);
self::assertSame(1, LadestationRegler::normalisiereStatus($rohstatus, false, false, true, true, 3)['Phasenzahl']);
$rohstatus['Istleistung_W'] = 11000.0;
self::assertSame(3, LadestationRegler::normalisiereStatus($rohstatus, false)['Phasenzahl']);
}
public function testUnbekanntePhasenHabenNurKonservativesStartbudget(): void
{
self::assertSame([0], LadestationRegler::leistungsangebot(true, true, true, false, 0, 16, true, true));
self::assertSame([0, 4104], LadestationRegler::leistungsangebot(true, true, true, false, 0, 16, false, true));
self::assertSame([0], LadestationRegler::leistungsangebot(false, true, true, false, 0, 16, false, false));
self::assertSame([0], LadestationRegler::leistungsangebot(true, false, true, false, 0, 16, false, false));
self::assertSame(0, LadestationRegler::stromFuerLeistung(4103, 0));
self::assertSame(6, LadestationRegler::stromFuerLeistung(4104, 0));
self::assertSame(6, LadestationRegler::stromFuerLeistung(22000, 0));
}
public function testDirekterPhasenstromHatVorrangVorNominalerLeistungsumrechnung(): void