feat(application): integrate measured-load ingestion training and planner source
This commit is contained in:
+113
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Belevo\EnelixEMS\Tests;
|
||||
|
||||
use Belevo\EnelixEMS\NetzfahrplanV4Bezugszaehler as Meter;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/** Offline only: injected readings, no Symcon, archive, network or actuator access. */
|
||||
final class V4BezugszaehlerScenarios
|
||||
{
|
||||
public static function run(): array
|
||||
{
|
||||
$now = 1790874000;
|
||||
$sources = [
|
||||
['VariableID' => 59607, 'ElternID' => 11490, 'Ident' => 'Energy_0', 'FaktorZuKWh' => 1.0, 'Messgroesse' => 'WirkenergieBezug'],
|
||||
['VariableID' => 26620, 'ElternID' => 11490, 'Ident' => 'Energy_1', 'FaktorZuKWh' => 1.0, 'Messgroesse' => 'WirkenergieBezug'],
|
||||
];
|
||||
$samples = [
|
||||
59607 => ['value' => 3992.203, 'updated' => $now, 'parentID' => 11490, 'ident' => 'Energy_0'],
|
||||
26620 => ['value' => 0.0, 'updated' => $now, 'parentID' => 11490, 'ident' => 'Energy_1'],
|
||||
];
|
||||
$check = static function (bool $value): void { if (!$value) { throw new RuntimeException('Assertion failed'); } };
|
||||
$reject = static function (callable $fn): void {
|
||||
try { $fn(); } catch (InvalidArgumentException $e) { return; }
|
||||
throw new RuntimeException('Expected invalid source/sample rejection');
|
||||
};
|
||||
$snapshot = static function ($ss = null, $mm = null) use ($sources, $samples, $now): array {
|
||||
$mm = $mm ?? $samples;
|
||||
return Meter::lesen($ss ?? $sources, static fn(int $id) => $mm[$id] ?? null, $now);
|
||||
};
|
||||
$cases = [];
|
||||
$cases['zero_t2_is_valid_but_not_history'] = static function () use ($snapshot, $check): void {
|
||||
$v = $snapshot();
|
||||
$check(abs($v['totalKwh'] - 3992.203) < 1e-9 && !$v['historyComplete'] && !$v['billingEvidence']);
|
||||
$check(!isset($v['measuredPeaks']) && !isset($v['quarterPast']));
|
||||
};
|
||||
$cases['both_tariffs_are_summed'] = static function () use ($snapshot, $samples, $check): void {
|
||||
$samples[26620]['value'] = 27.25;
|
||||
$check(abs($snapshot(null, $samples)['totalKwh'] - 4019.453) < 1e-9);
|
||||
};
|
||||
$cases['zero_total_not_replaced'] = static function () use ($snapshot, $samples, $check): void {
|
||||
$samples[59607]['value'] = 0;
|
||||
$check($snapshot(null, $samples)['totalKwh'] === 0.0);
|
||||
};
|
||||
$cases['source_order_does_not_change_identity'] = static function () use ($sources, $check): void {
|
||||
$check(Meter::identitaet($sources) === Meter::identitaet(array_reverse($sources)));
|
||||
};
|
||||
$cases['changed_factor_invalidates_identity'] = static function () use ($sources, $check): void {
|
||||
$old = Meter::identitaet($sources); $sources[0]['FaktorZuKWh'] = 0.001;
|
||||
$check($old !== Meter::identitaet($sources));
|
||||
};
|
||||
$cases['changed_variable_invalidates_identity'] = static function () use ($sources, $check): void {
|
||||
$old = Meter::identitaet($sources); $sources[0]['VariableID'] = 12345;
|
||||
$check($old !== Meter::identitaet($sources));
|
||||
};
|
||||
$cases['no_fallback_to_legacy_source'] = static function () use ($snapshot, $reject): void { $reject(static fn() => $snapshot([])); };
|
||||
$cases['duplicate_variable_rejected'] = static function () use ($sources, $snapshot, $reject): void {
|
||||
$sources[1] = $sources[0]; $reject(static fn() => $snapshot($sources));
|
||||
};
|
||||
$cases['different_meter_boundary_rejected'] = static function () use ($sources, $snapshot, $reject): void {
|
||||
$sources[1]['ElternID'] = 48065; $reject(static fn() => $snapshot($sources));
|
||||
};
|
||||
$cases['reactive_quantity_rejected'] = static function () use ($sources, $snapshot, $reject): void {
|
||||
$sources[0]['Messgroesse'] = 'Blindenergie'; $reject(static fn() => $snapshot($sources));
|
||||
};
|
||||
$cases['explicit_conversion_required'] = static function () use ($sources, $snapshot, $reject): void {
|
||||
unset($sources[0]['FaktorZuKWh']); $reject(static fn() => $snapshot($sources));
|
||||
};
|
||||
$cases['missing_tariff_not_zero'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
unset($samples[26620]); $reject(static fn() => $snapshot(null, $samples));
|
||||
};
|
||||
$cases['stale_zero_tariff_rejected'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
$samples[26620]['updated'] -= 61; $reject(static fn() => $snapshot(null, $samples));
|
||||
};
|
||||
$cases['future_reading_rejected'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
$samples[26620]['updated']++; $reject(static fn() => $snapshot(null, $samples));
|
||||
};
|
||||
$cases['wrong_ident_rejected'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
$samples[59607]['ident'] = 'Energy_6'; $reject(static fn() => $snapshot(null, $samples));
|
||||
};
|
||||
$cases['wrong_parent_rejected'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
$samples[59607]['parentID'] = 48065; $reject(static fn() => $snapshot(null, $samples));
|
||||
};
|
||||
$cases['invalid_numbers_rejected'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
foreach ([false, '3992.203', NAN, INF, -1.0] as $bad) {
|
||||
$samples[59607]['value'] = $bad; $reject(static fn() => $snapshot(null, $samples));
|
||||
}
|
||||
};
|
||||
$cases['skewed_tariff_observations_rejected'] = static function () use ($snapshot, $samples, $reject): void {
|
||||
$samples[59607]['updated'] -= 3; $reject(static fn() => $snapshot(null, $samples));
|
||||
};
|
||||
$cases['concurrent_update_in_same_second_rejected'] = static function () use ($sources, $samples, $now, $reject): void {
|
||||
$calls = 0;
|
||||
$read = static function (int $id) use ($samples, &$calls): array {
|
||||
$v = $samples[$id]; if (++$calls > 2) { $v['value'] += 0.1; } return $v;
|
||||
};
|
||||
$reject(static fn() => Meter::lesen($sources, $read, $now));
|
||||
};
|
||||
$cases['observation_not_fake_exact_billing_time'] = static function () use ($snapshot, $samples, $now, $check): void {
|
||||
$samples[59607]['updated'] -= 1;
|
||||
$v = $snapshot(null, $samples);
|
||||
$check($v['sourceObservationFrom'] === gmdate('c', $now - 1));
|
||||
$check($v['sourceObservationUntil'] === gmdate('c', $now) && $v['observedAt'] === gmdate('c', $now));
|
||||
$check(!$v['billingEvidence']);
|
||||
};
|
||||
$passed = [];
|
||||
foreach ($cases as $name => $fn) { $fn(); $passed[] = $name; }
|
||||
return $passed;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user