162 lines
4.9 KiB
PHP
162 lines
4.9 KiB
PHP
<?php
|
|
|
|
class MeterValueNormalizer
|
|
{
|
|
public function normalize(array $payload): array
|
|
{
|
|
$result = [
|
|
'powerImportW' => null,
|
|
'powerExportW' => null,
|
|
'energyImportWh' => null,
|
|
'energyExportWh' => null,
|
|
'currentA' => [1 => null, 2 => null, 3 => null],
|
|
'voltageV' => [1 => null, 2 => null, 3 => null],
|
|
'powerPhaseW' => [1 => null, 2 => null, 3 => null],
|
|
'soc' => null,
|
|
'temperature' => null,
|
|
'quality' => 'OCPP-MeterValue',
|
|
'timestamp' => time()
|
|
];
|
|
|
|
foreach ($this->extractSamples($payload) as $sample) {
|
|
$measurand = (string)($sample['measurand'] ?? 'Energy.Active.Import.Register');
|
|
$value = $this->normalizeValue($sample);
|
|
$phase = $this->phaseIndex((string)($sample['phase'] ?? ''));
|
|
|
|
switch ($measurand) {
|
|
case 'Power.Active.Import':
|
|
$this->writePower($result, 'powerImportW', $value, $phase);
|
|
break;
|
|
case 'Power.Active.Export':
|
|
$this->writePower($result, 'powerExportW', $value, $phase);
|
|
break;
|
|
case 'Energy.Active.Import.Register':
|
|
case 'Energy.Active.Import.Interval':
|
|
$result['energyImportWh'] = $value;
|
|
break;
|
|
case 'Energy.Active.Export.Register':
|
|
case 'Energy.Active.Export.Interval':
|
|
$result['energyExportWh'] = $value;
|
|
break;
|
|
case 'Current.Import':
|
|
if ($phase > 0) {
|
|
$result['currentA'][$phase] = $value;
|
|
}
|
|
break;
|
|
case 'Voltage':
|
|
if ($phase > 0) {
|
|
$result['voltageV'][$phase] = $value;
|
|
}
|
|
break;
|
|
case 'SoC':
|
|
$result['soc'] = $value;
|
|
break;
|
|
case 'Temperature':
|
|
$result['temperature'] = $value;
|
|
break;
|
|
}
|
|
|
|
if (isset($sample['timestamp'])) {
|
|
$ts = strtotime((string)$sample['timestamp']);
|
|
if ($ts !== false) {
|
|
$result['timestamp'] = $ts;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($result['powerImportW'] === null) {
|
|
$result['powerImportW'] = $this->sumPhases($result['powerPhaseW']);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function extractSamples(array $payload): array
|
|
{
|
|
$samples = [];
|
|
$containers = $payload['meterValue'] ?? $payload['meterValues'] ?? [$payload];
|
|
if (!is_array($containers)) {
|
|
return [];
|
|
}
|
|
|
|
foreach ($containers as $container) {
|
|
if (!is_array($container)) {
|
|
continue;
|
|
}
|
|
$timestamp = $container['timestamp'] ?? null;
|
|
$sampled = $container['sampledValue'] ?? $container['sampledValues'] ?? [];
|
|
if (!is_array($sampled)) {
|
|
continue;
|
|
}
|
|
foreach ($sampled as $sample) {
|
|
if (!is_array($sample)) {
|
|
continue;
|
|
}
|
|
if ($timestamp !== null && !isset($sample['timestamp'])) {
|
|
$sample['timestamp'] = $timestamp;
|
|
}
|
|
$samples[] = $sample;
|
|
}
|
|
}
|
|
|
|
return $samples;
|
|
}
|
|
|
|
private function normalizeValue(array $sample): float
|
|
{
|
|
$rawValue = $sample['value'] ?? 0;
|
|
if (is_array($rawValue)) {
|
|
$rawValue = $rawValue['value'] ?? 0;
|
|
}
|
|
$value = (float)$rawValue;
|
|
$unit = $sample['unit'] ?? ($sample['unitOfMeasure']['unit'] ?? '');
|
|
$unit = strtolower((string)$unit);
|
|
|
|
if ($unit === 'kwh') {
|
|
return $value * 1000.0;
|
|
}
|
|
if ($unit === 'kw') {
|
|
return $value * 1000.0;
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
private function phaseIndex(string $phase): int
|
|
{
|
|
if (stripos($phase, 'L1') !== false) {
|
|
return 1;
|
|
}
|
|
if (stripos($phase, 'L2') !== false) {
|
|
return 2;
|
|
}
|
|
if (stripos($phase, 'L3') !== false) {
|
|
return 3;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private function writePower(array &$result, string $key, float $value, int $phase): void
|
|
{
|
|
if ($phase > 0) {
|
|
$result['powerPhaseW'][$phase] = $value;
|
|
return;
|
|
}
|
|
$result[$key] = $value;
|
|
}
|
|
|
|
private function sumPhases(array $values): ?float
|
|
{
|
|
$sum = 0.0;
|
|
$found = false;
|
|
foreach ($values as $value) {
|
|
if ($value !== null) {
|
|
$sum += (float)$value;
|
|
$found = true;
|
|
}
|
|
}
|
|
return $found ? $sum : null;
|
|
}
|
|
}
|
|
|
|
?>
|