174 lines
7.4 KiB
PHP
Executable File
174 lines
7.4 KiB
PHP
Executable File
<?php
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\StabileServizio;
|
|
use App\Models\StabileServizioLettura;
|
|
use App\Models\UnitaImmobiliare;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class WaterMeterGatewayController extends Controller
|
|
{
|
|
public function storeReading(Request $request): JsonResponse
|
|
{
|
|
$expectedToken = trim((string) config('services.water_gateway.token', ''));
|
|
if ($expectedToken !== '') {
|
|
$provided = trim((string) ($request->header('X-Netgescon-Water-Token') ?: $request->bearerToken() ?: $request->query('token', '')));
|
|
if (! hash_equals($expectedToken, $provided)) {
|
|
return response()->json(['ok' => false, 'message' => 'Token gateway non valido'], 403);
|
|
}
|
|
} elseif (! app()->environment(['local', 'testing'])) {
|
|
return response()->json(['ok' => false, 'message' => 'Token gateway acqua non configurato'], 503);
|
|
}
|
|
|
|
$data = $request->validate([
|
|
'device_id' => ['nullable', 'string', 'max:120'],
|
|
'serial' => ['nullable', 'string', 'max:100'],
|
|
'unita_id' => ['nullable', 'integer'],
|
|
'value' => ['required', 'numeric'],
|
|
'read_at' => ['nullable', 'date'],
|
|
'unit' => ['nullable', 'string', 'max:20'],
|
|
'battery' => ['nullable', 'numeric'],
|
|
'rssi' => ['nullable', 'numeric'],
|
|
'payload' => ['nullable', 'array'],
|
|
]);
|
|
|
|
$unita = $this->resolveUnita($data);
|
|
if (! $unita instanceof UnitaImmobiliare) {
|
|
return response()->json(['ok' => false, 'message' => 'Unità non trovata per device_id/seriale'], 404);
|
|
}
|
|
|
|
$servizio = StabileServizio::query()
|
|
->where('stabile_id', (int) $unita->stabile_id)
|
|
->where('tipo', 'acqua')
|
|
->where('attivo', true)
|
|
->orderBy('id')
|
|
->first();
|
|
|
|
if (! $servizio instanceof StabileServizio) {
|
|
$servizio = StabileServizio::query()->create([
|
|
'stabile_id' => (int) $unita->stabile_id,
|
|
'tipo' => 'acqua',
|
|
'nome' => 'Acqua - gateway contatori',
|
|
'contatore_matricola' => trim((string) ($data['serial'] ?? '')) ?: null,
|
|
'attivo' => true,
|
|
'meta' => ['source' => 'water_gateway_auto'],
|
|
]);
|
|
}
|
|
|
|
$readAt = isset($data['read_at']) && $data['read_at'] ? Carbon::parse($data['read_at']) : now();
|
|
$value = round((float) $data['value'], 3);
|
|
|
|
$previous = StabileServizioLettura::query()
|
|
->where('unita_immobiliare_id', (int) $unita->id)
|
|
->where('stabile_servizio_id', (int) $servizio->id)
|
|
->whereNotNull('lettura_fine')
|
|
->orderByDesc('periodo_al')
|
|
->orderByDesc('id')
|
|
->first();
|
|
|
|
$previousValue = $previous instanceof StabileServizioLettura ? (float) $previous->lettura_fine : null;
|
|
$consumption = $previousValue !== null ? max(0, round($value - $previousValue, 3)) : 0.0;
|
|
|
|
$reading = StabileServizioLettura::query()->create([
|
|
'stabile_id' => (int) $unita->stabile_id,
|
|
'stabile_servizio_id' => (int) $servizio->id,
|
|
'unita_immobiliare_id' => (int) $unita->id,
|
|
'periodo_dal' => $previous?->periodo_al ?: $readAt->toDateString(),
|
|
'periodo_al' => $readAt->toDateString(),
|
|
'tipologia_lettura' => 'reale',
|
|
'canale_acquisizione' => 'gateway',
|
|
'riferimento_acquisizione' => trim((string) ($data['device_id'] ?? $data['serial'] ?? 'gateway')),
|
|
'workflow_stato' => 'acquisita',
|
|
'rilevatore_tipo' => 'gateway_iot',
|
|
'rilevatore_nome' => trim((string) ($data['device_id'] ?? 'gateway')),
|
|
'lettura_precedente_valore' => $previousValue,
|
|
'lettura_inizio' => $previousValue,
|
|
'lettura_fine' => $value,
|
|
'consumo_valore' => $consumption,
|
|
'consumo_unita' => trim((string) ($data['unit'] ?? 'mc')) ?: 'mc',
|
|
'raw' => [
|
|
'source' => 'water_meter_gateway',
|
|
'device_id' => $data['device_id'] ?? null,
|
|
'serial' => $data['serial'] ?? null,
|
|
'battery' => $data['battery'] ?? null,
|
|
'rssi' => $data['rssi'] ?? null,
|
|
'payload' => $data['payload'] ?? [],
|
|
],
|
|
]);
|
|
|
|
$this->updateUnitGatewayFields($unita, $data);
|
|
|
|
return response()->json([
|
|
'ok' => true,
|
|
'reading_id' => (int) $reading->id,
|
|
'unita_id' => (int) $unita->id,
|
|
'stabile_id' => (int) $unita->stabile_id,
|
|
'stabile_servizio_id' => (int) $servizio->id,
|
|
'lettura_fine' => $value,
|
|
'consumo' => $consumption,
|
|
]);
|
|
}
|
|
|
|
/** @param array<string,mixed> $data */
|
|
private function resolveUnita(array $data): ?UnitaImmobiliare
|
|
{
|
|
$query = UnitaImmobiliare::query();
|
|
if (Schema::hasColumn('unita_immobiliari', 'deleted_at')) {
|
|
$query->whereNull('deleted_at');
|
|
}
|
|
|
|
if (! empty($data['unita_id'])) {
|
|
$found = (clone $query)->whereKey((int) $data['unita_id'])->first();
|
|
if ($found instanceof UnitaImmobiliare) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
$deviceId = trim((string) ($data['device_id'] ?? ''));
|
|
if ($deviceId !== '' && Schema::hasColumn('unita_immobiliari', 'acqua_gateway_device_id')) {
|
|
$found = (clone $query)->where('acqua_gateway_device_id', $deviceId)->first();
|
|
if ($found instanceof UnitaImmobiliare) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
$serial = trim((string) ($data['serial'] ?? ''));
|
|
if ($serial !== '' && Schema::hasColumn('unita_immobiliari', 'acqua_contatore_seriale')) {
|
|
$found = (clone $query)->where('acqua_contatore_seriale', $serial)->first();
|
|
if ($found instanceof UnitaImmobiliare) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/** @param array<string,mixed> $data */
|
|
private function updateUnitGatewayFields(UnitaImmobiliare $unita, array $data): void
|
|
{
|
|
$patch = [];
|
|
if (empty($unita->acqua_gateway_device_id) && ! empty($data['device_id'])) {
|
|
$patch['acqua_gateway_device_id'] = trim((string) $data['device_id']);
|
|
}
|
|
if (empty($unita->acqua_contatore_seriale) && ! empty($data['serial'])) {
|
|
$patch['acqua_contatore_seriale'] = trim((string) $data['serial']);
|
|
}
|
|
if (Schema::hasColumn('unita_immobiliari', 'acqua_gateway_meta')) {
|
|
$patch['acqua_gateway_meta'] = array_filter([
|
|
'last_seen_at' => now()->toIso8601String(),
|
|
'battery' => $data['battery'] ?? null,
|
|
'rssi' => $data['rssi'] ?? null,
|
|
], static fn($value): bool => $value !== null);
|
|
}
|
|
|
|
if ($patch !== []) {
|
|
$unita->fill($patch);
|
|
$unita->save();
|
|
}
|
|
}
|
|
}
|