false, 'message' => 'Método no permitido. Use POST.' ]); exit(); } // Validar token de seguridad $headers = getallheaders(); $auth_header = $headers['Authorization'] ?? $headers['authorization'] ?? ''; $post_token = $_POST['token'] ?? ''; $token_valido = false; if ($auth_header === 'Bearer ' . IOT_API_TOKEN || $post_token === IOT_API_TOKEN) { $token_valido = true; } // MODO DEBUG: Si quieres probar sin token, descomenta la siguiente línea: // $token_valido = true; if (!$token_valido) { http_response_code(401); echo json_encode(['success' => false, 'message' => 'NO_AUTORIZADO: Token inválido']); exit(); } // Obtener y sanitizar datos del ESP32 $cabina_id = isset($_POST['cabina_id']) ? (int)$_POST['cabina_id'] : (isset($_POST['jaula_id']) ? (int)$_POST['jaula_id'] : null); $temp = isset($_POST['temp']) ? filter_var($_POST['temp'], FILTER_VALIDATE_FLOAT) : null; $hum = isset($_POST['hum']) ? filter_var($_POST['hum'], FILTER_VALIDATE_FLOAT) : null; $aire = isset($_POST['aire']) ? filter_var($_POST['aire'], FILTER_VALIDATE_INT) : null; $agua = isset($_POST['agua']) ? (int)$_POST['agua'] : null; // Validar que al menos tenemos el ID de la cabina if (!$cabina_id) { http_response_code(400); echo json_encode([ 'success' => false, 'message' => 'Falta el parámetro obligatorio: cabina_id (o jaula_id)' ]); exit(); } // Validar rangos físicos razonables if ($temp !== null && ($temp < -40 || $temp > 80)) $temp = null; if ($hum !== null && ($hum < 0 || $hum > 100)) $hum = null; if ($aire !== null && ($aire < 0 || $aire > 4095)) $aire = null; if ($agua !== null) $agua = $agua ? 1 : 0; // Verificar que la cabina existe $stmtCheck = $pdo->prepare("SELECT id FROM cabinas WHERE id = :id LIMIT 1"); $stmtCheck->execute([':id' => $cabina_id]); if (!$stmtCheck->fetch()) { http_response_code(404); echo json_encode([ 'success' => false, 'message' => 'Cabina no encontrada' ]); exit(); } // Buscar si hay una reserva activa en esta cabina $reserva_id = null; $stmtReserva = $pdo->prepare(" SELECT id FROM reservas WHERE cabina_id = :cabina_id AND estado IN ('confirmada', 'activa') ORDER BY id DESC LIMIT 1 "); $stmtReserva->execute([':cabina_id' => $cabina_id]); $reserva = $stmtReserva->fetch(); if ($reserva) { $reserva_id = $reserva['id']; } // Iniciar transacción $pdo->beginTransaction(); try { // 1. Insertar registro en la tabla histórica de telemetría $stmtInsert = $pdo->prepare(" INSERT INTO telemetria (reserva_id, cabina_id, temperatura, humedad, calidad_aire, nivel_agua) VALUES (:reserva_id, :cabina_id, :temp, :hum, :aire, :agua) "); $stmtInsert->execute([ ':reserva_id' => $reserva_id, ':cabina_id' => $cabina_id, ':temp' => $temp, ':hum' => $hum, ':aire' => $aire, ':agua' => $agua ]); // 2. Actualizar la tabla cabinas con los últimos valores $stmtUpdate = $pdo->prepare(" UPDATE cabinas SET temperatura_actual = :temp, humedad_actual = :hum, calidad_aire_actual = :aire, nivel_agua = :agua, ultima_telemetria = NOW() WHERE id = :id "); $stmtUpdate->execute([ ':temp' => $temp, ':hum' => $hum, ':aire' => $aire, ':agua' => $agua, ':id' => $cabina_id ]); // Confirmar transacción $pdo->commit(); // Responder con éxito echo json_encode([ 'success' => true, 'message' => 'OK', 'data' => [ 'cabina_id' => $cabina_id, 'reserva_id' => $reserva_id, 'timestamp' => date('Y-m-d H:i:s') ] ]); } catch (PDOException $e) { // Revertir transacción en caso de error $pdo->rollBack(); throw $e; } } catch (PDOException $e) { http_response_code(500); echo json_encode([ 'success' => false, 'message' => 'Error en el servidor', 'error' => $e->getMessage() ]); } catch (Exception $e) { http_response_code(500); echo json_encode([ 'success' => false, 'message' => 'Error inesperado', 'error' => $e->getMessage() ]); } ?>