99999) { throw new InvalidArgumentException('feedback_auto_battery_measurements_missing'); } } if (($controller['IstleistungVariableID'] ?? null) !== $asset['LeistungVariableID'] || ($controller['LadezustandVariableID'] ?? null) !== $asset['SOCVariableID'] || $asset['SOCVariableID'] === $asset['LeistungVariableID']) { throw new InvalidArgumentException('feedback_auto_controller_measurements_differ'); } if ((!is_int($asset['Leistungsfaktor'] ?? null) && !is_float($asset['Leistungsfaktor'] ?? null)) || (float) $asset['Leistungsfaktor'] !== 1.0) { throw new InvalidArgumentException('feedback_auto_controller_units_differ'); } $maxAge = $controller['MesswertMaxAlter'] ?? null; if (!is_int($maxAge) || $maxAge < 1) { throw new InvalidArgumentException('feedback_auto_controller_freshness_invalid'); } $maxAge = min(60, $maxAge); $sources = []; $roles = []; foreach ($capture['accounting']['sources'] as $source) { if ($source['dependsOn'] !== [] || !in_array($source['role'], ['grid', 'pv', 'physical_storage'], true)) { throw new InvalidArgumentException('feedback_auto_derived_source_refused'); } if (!in_array($source['role'], ['grid', 'physical_storage'], true)) { continue; } $roles[$source['role']] = ($roles[$source['role']] ?? 0) + 1; // The ordinary battery module consumes these same variables as W. if ($source['factorToW'] !== 1.0) { throw new InvalidArgumentException('feedback_auto_controller_units_differ'); } if (($source['role'] === 'grid' && $source['variableId'] !== ($controller['NetzleistungVariableID'] ?? null)) || ($source['role'] === 'physical_storage' && $source['variableId'] !== $asset['LeistungVariableID']) || $source['variableId'] === $asset['SOCVariableID']) { throw new InvalidArgumentException('feedback_auto_source_binding_invalid'); } $expectedKey = $source['role'] === 'grid' ? 'grid' : 'battery_' . substr(hash('sha256', trim($assetId)), 0, 24); if ($source['key'] !== $expectedKey) { throw new InvalidArgumentException('feedback_auto_source_identity_changed'); } $maxAge = min($maxAge, $source['maxAgeSeconds']); $sources[] = [ 'key' => $source['key'], 'role' => $source['role'] === 'grid' ? 'grid' : 'physical', 'variableId' => $source['variableId'], 'parentId' => $source['parentId'], 'ident' => $source['ident'], 'factorToW' => $source['factorToW'], ]; } if (($roles['grid'] ?? 0) !== 1 || ($roles['physical_storage'] ?? 0) !== 1) { throw new InvalidArgumentException('feedback_auto_physical_sources_ambiguous'); } return NetzfahrplanV4Rueckmeldung::configuration([ 'version' => 1, 'installationId' => $installationId, 'assetId' => trim($assetId), 'managerId' => $managerId, 'batteryInstanceId' => $batteryId, 'mode' => 'physical_sum', 'allowEstimatedForTrial' => false, 'maxAgeSeconds' => $maxAge, 'maxSkewSeconds' => min(30, $maxAge, $capture['accounting']['maxSkewSeconds']), 'idleToleranceW' => 0.0, 'trackingToleranceW' => 0.0, 'sources' => $sources, ]); } }