nasa-power-api-client
Version:
Cliente TypeScript para la API NASA POWER enfocado en datos meteorológicos de España
663 lines (662 loc) • 30.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NasaPowerClient = void 0;
const axios_1 = __importDefault(require("axios"));
const types_1 = require("./types");
/**
* Cliente para la API de NASA POWER
*/
class NasaPowerClient {
/**
* Constructor
*/
constructor() {
this.apiBaseUrl = 'https://power.larc.nasa.gov/api/temporal/daily/point';
this.axiosInstance = axios_1.default.create({
baseURL: this.apiBaseUrl,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
});
}
/**
* Obtiene datos meteorológicos para una ubicación específica
* @param options Opciones de la petición
* @returns Promesa con los datos meteorológicos
*/
async getWeatherData(options) {
try {
const response = await this.makeApiRequest(options);
return this.processApiResponse(response.data);
}
catch (error) {
console.error('Error al obtener datos meteorológicos:', error);
throw error;
}
}
/**
* Obtiene datos meteorológicos para una región de España
* @param region Región española
* @param startDate Fecha de inicio (YYYYMMDD)
* @param endDate Fecha de fin (YYYYMMDD)
* @param parameters Parámetros meteorológicos a obtener
* @returns Promesa con los datos meteorológicos
*/
async getWeatherDataForSpanishRegion(region, startDate, endDate, parameters = [
types_1.MeteoParam.T2M,
types_1.MeteoParam.T2M_MAX,
types_1.MeteoParam.T2M_MIN,
types_1.MeteoParam.PRECTOTCORR,
types_1.MeteoParam.RH2M,
types_1.MeteoParam.WS10M,
types_1.MeteoParam.TSOIL1,
types_1.MeteoParam.TSOIL2,
types_1.MeteoParam.EVLAND,
types_1.MeteoParam.ALLSKY_SFC_PAR_TOT
]) {
const coordinates = types_1.SPANISH_REGION_COORDINATES[region];
if (!coordinates) {
throw new Error(`No se encontraron coordenadas para la región: ${region}`);
}
return this.getWeatherData({
coordinates,
startDate,
endDate,
parameters,
format: types_1.ResponseFormat.JSON,
community: 'SB' // Science/Research & Education
});
}
/**
* Obtiene datos agroclimáticos completos para una región de España
* @param region Región española
* @param startDate Fecha de inicio (YYYYMMDD)
* @param endDate Fecha de fin (YYYYMMDD)
* @returns Datos meteorológicos con índices agroclimáticos y recomendaciones
*/
async getAgriculturalData(region, startDate, endDate) {
// Limitamos a un máximo de 20 parámetros según la documentación de la API
// Obtenemos los 20 parámetros más importantes para la agricultura
const parameters = [
types_1.MeteoParam.T2M,
types_1.MeteoParam.T2M_MAX,
types_1.MeteoParam.T2M_MIN,
types_1.MeteoParam.PRECTOTCORR,
types_1.MeteoParam.RH2M,
types_1.MeteoParam.WS10M,
types_1.MeteoParam.WD10M,
types_1.MeteoParam.PS,
types_1.MeteoParam.CLOUD_AMT,
types_1.MeteoParam.ALLSKY_SFC_SW_DWN,
types_1.MeteoParam.TSOIL1,
types_1.MeteoParam.TSOIL2,
types_1.MeteoParam.GWETROOT,
types_1.MeteoParam.GWETTOP,
types_1.MeteoParam.EVLAND,
types_1.MeteoParam.ALLSKY_SFC_PAR_TOT,
types_1.MeteoParam.T2MDEW,
types_1.MeteoParam.T2MWET
];
const weatherData = await this.getWeatherDataForSpanishRegion(region, startDate, endDate, parameters);
// Calculamos los índices agroclimáticos
const indices = weatherData.map(data => this.calculateAgroClimateIndices(data));
// Generamos recomendaciones
const recommendations = weatherData.map((data, index) => this.generateRecommendations(data, indices[index]));
return {
weatherData,
indices,
recommendations
};
}
/**
* Comprueba si está lloviendo en una región española
* @param region Región española
* @returns Promesa que indica si está lloviendo (true) o no (false)
*/
async isRaining(region) {
// Obtenemos los datos de hoy
const today = new Date();
const formattedDate = this.formatDate(today);
const weatherData = await this.getWeatherDataForSpanishRegion(region, formattedDate, formattedDate, [types_1.MeteoParam.PRECTOTCORR]);
if (weatherData.length === 0) {
throw new Error('No se obtuvieron datos meteorológicos');
}
// Si la precipitación es mayor a 0, está lloviendo
return (weatherData[0].precipitation || 0) > 0;
}
/**
* Determina si es adecuado regar los cultivos
* @param region Región española
* @returns Información sobre necesidad de riego
*/
async shouldIrrigate(region) {
// Obtenemos datos de los últimos 3 días para análisis
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 2);
const endDateStr = this.formatDate(endDate);
const startDateStr = this.formatDate(startDate);
const weatherData = await this.getWeatherDataForSpanishRegion(region, startDateStr, endDateStr, [
types_1.MeteoParam.PRECTOTCORR,
types_1.MeteoParam.T2M,
types_1.MeteoParam.RH2M,
types_1.MeteoParam.TSOIL1,
types_1.MeteoParam.EVLAND
]);
if (weatherData.length === 0) {
throw new Error('No se obtuvieron datos meteorológicos');
}
// Datos del día actual
const today = weatherData[weatherData.length - 1];
// Verificar si hay valores -999 o datos críticos en 0 (datos no disponibles)
if (today.precipitation === -999 || today.soilMoisture === -999 ||
today.evapotranspiration === -999 || today.soilMoisture === 0) {
return {
shouldIrrigate: 'no definido',
reason: 'No hay datos suficientes para determinar la necesidad de riego.'
};
}
// Si ha llovido hoy, no es necesario regar
if ((today.precipitation || 0) > 5) {
return {
shouldIrrigate: false,
reason: `Ha llovido suficiente hoy (${today.precipitation} mm), no es necesario regar.`
};
}
// Calculamos la necesidad de riego basada en evapotranspiración y humedad del suelo
const soilMoisture = today.soilMoisture || 0;
const evapotranspiration = today.evapotranspiration || 0;
// Si hay baja humedad del suelo y alta evapotranspiración, se recomienda regar
if (soilMoisture < 30 && evapotranspiration > 4) {
// Calculamos cantidad recomendada
const recommendedAmount = Math.round((30 - soilMoisture) * 0.5);
return {
shouldIrrigate: true,
reason: `Baja humedad del suelo (${soilMoisture}%) y alta evapotranspiración (${evapotranspiration} mm/día).`,
recommendedAmount
};
}
return {
shouldIrrigate: false,
reason: `Condiciones adecuadas: humedad del suelo (${soilMoisture}%) y evapotranspiración (${evapotranspiration} mm/día).`
};
}
/**
* Comprueba el riesgo de heladas para los cultivos
* @param region Región española
* @returns Información sobre riesgo de heladas
*/
async checkFrostRisk(region) {
// Obtenemos previsión para próximos 2 días
const startDate = new Date();
const endDate = new Date();
endDate.setDate(endDate.getDate() + 1);
const startDateStr = this.formatDate(startDate);
const endDateStr = this.formatDate(endDate);
const weatherData = await this.getWeatherDataForSpanishRegion(region, startDateStr, endDateStr, [types_1.MeteoParam.T2M_MIN]);
if (weatherData.length === 0) {
throw new Error('No se obtuvieron datos meteorológicos');
}
// Analizamos las temperaturas mínimas previstas
const minTemps = weatherData.map(data => data.minTemperature || 0);
// Verificar si hay algún valor -999 o 0 (dato no disponible)
if (minTemps.some(temp => temp === -999 || temp === 0)) {
return {
riskLevel: 'no definido',
message: 'No hay datos disponibles para determinar el riesgo de heladas.'
};
}
const lowestTemp = Math.min(...minTemps);
if (lowestTemp <= 0) {
return {
riskLevel: 'alto',
message: `¡ALERTA! Riesgo alto de heladas. Temperatura mínima prevista: ${lowestTemp}°C. Se recomienda proteger cultivos sensibles.`
};
}
else if (lowestTemp <= 3) {
return {
riskLevel: 'medio',
message: `Riesgo medio de heladas. Temperatura mínima prevista: ${lowestTemp}°C. Considere medidas preventivas para cultivos sensibles.`
};
}
else {
return {
riskLevel: 'bajo',
message: `Riesgo bajo de heladas. Temperatura mínima prevista: ${lowestTemp}°C.`
};
}
}
/**
* Verifica condiciones óptimas para siembra
* @param region Región española
* @returns Información sobre condiciones de siembra
*/
async checkPlantingConditions(region) {
// Obtenemos datos actuales y previsión para mañana
const today = new Date();
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
const todayStr = this.formatDate(today);
const tomorrowStr = this.formatDate(tomorrow);
const weatherData = await this.getWeatherDataForSpanishRegion(region, todayStr, tomorrowStr, [types_1.MeteoParam.TSOIL1, types_1.MeteoParam.TSOIL2, types_1.MeteoParam.PRECTOTCORR, types_1.MeteoParam.T2M]);
if (weatherData.length === 0) {
throw new Error('No se obtuvieron datos meteorológicos');
}
const currentData = weatherData[0];
const forecastData = weatherData.length > 1 ? weatherData[1] : null;
const soilMoisture = currentData.soilMoisture || 0;
const soilTemperature = currentData.soilTemperature || 0;
const rain = currentData.precipitation || 0;
const forecastRain = forecastData ? (forecastData.precipitation || 0) > 1 : false;
// Verificar valores -999 o soilMoisture y soilTemperature en 0 (datos no disponibles)
if (soilMoisture === -999 || soilTemperature === -999 || rain === -999 ||
soilMoisture === 0 || soilTemperature === 0 ||
(forecastData && forecastData.precipitation === -999)) {
return {
isOptimal: 'no definido',
message: 'No hay datos suficientes para determinar condiciones de siembra.',
details: {
soilMoisture,
soilTemperature,
rain,
forecastRain
}
};
}
// Condiciones óptimas: suelo húmedo pero no encharcado, temperatura adecuada y sin lluvia inminente
const isOptimal = soilMoisture >= 30 && soilMoisture <= 70 &&
soilTemperature >= 10 &&
rain < 5 &&
!forecastRain;
const details = {
soilMoisture,
soilTemperature,
rain,
forecastRain
};
if (isOptimal) {
return {
isOptimal: true,
message: 'Condiciones óptimas para siembra. Humedad y temperatura del suelo adecuadas, sin lluvias previstas.',
details
};
}
else {
let message = 'Condiciones no óptimas para siembra:';
if (soilMoisture < 30) {
message += ' Suelo demasiado seco.';
}
else if (soilMoisture > 70) {
message += ' Suelo demasiado húmedo.';
}
if (soilTemperature < 10) {
message += ' Temperatura del suelo demasiado baja.';
}
if (rain >= 5) {
message += ' Lluvia reciente.';
}
if (forecastRain) {
message += ' Lluvia prevista para mañana.';
}
return {
isOptimal: false,
message,
details
};
}
}
/**
* Realiza una petición a la API de NASA POWER
* @param options Opciones de la petición
* @returns Promesa con la respuesta de la API
* @private
*/
async makeApiRequest(options) {
const { coordinates, startDate, endDate, parameters, format = types_1.ResponseFormat.JSON, community = 'SB' } = options;
const queryParams = {
parameters: parameters.join(','),
community,
latitude: coordinates.latitude.toString(),
longitude: coordinates.longitude.toString(),
start: startDate,
end: endDate,
format
};
//console.log('URL de la petición:', this.apiBaseUrl);
//console.log('Params de la petición:', queryParams);
try {
const response = await this.axiosInstance.get('', { params: queryParams });
//console.log('Respuesta recibida con status:', response.status);
//console.log('Respuesta headers:', JSON.stringify(response.headers, null, 2));
//console.log('Estructura de respuesta:', Object.keys(response.data));
return response;
}
catch (error) {
console.error('Error en la petición a NASA POWER API:');
if (axios_1.default.isAxiosError(error) && error.response) {
console.error('Status:', error.response.status);
console.error('Mensaje:', error.message);
console.error('Datos de respuesta:', JSON.stringify(error.response.data, null, 2));
}
else {
console.error('Error desconocido:', error);
}
throw error;
}
}
/**
* Procesa la respuesta de la API y la convierte en un formato más amigable
* @param response Respuesta de la API
* @returns Datos meteorológicos procesados
* @private
*/
processApiResponse(response) {
const results = [];
//console.log('Procesando respuesta API completa:', JSON.stringify(response, null, 2));
// Verificar que la respuesta tenga la estructura esperada
if (!response || !response.properties || !response.properties.parameter) {
console.warn('La respuesta de la API no tiene la estructura esperada:', response);
return results;
}
// La nueva estructura tiene los parámetros y sus valores en properties.parameter
const parameters = response.properties.parameter;
// Verificar si hay al menos un parámetro
const paramKeys = Object.keys(parameters);
if (paramKeys.length === 0) {
console.warn('No se encontraron parámetros en la respuesta');
return results;
}
//console.log('Parámetros encontrados en la respuesta:', paramKeys);
// Obtenemos las fechas (claves) de los parámetros
const firstParamKey = paramKeys[0];
if (!parameters[firstParamKey] || typeof parameters[firstParamKey] !== 'object') {
console.warn(`El parámetro ${firstParamKey} no tiene el formato esperado`);
return results;
}
// Obtenemos las fechas de los valores (no de las unidades)
const dates = Object.keys(parameters[firstParamKey]).filter(key => key !== 'units' && key !== 'longname');
// Filtrar las fechas no válidas
const validDates = dates.filter(date => {
// Verificar si es formato YYYYMMDD (8 caracteres y todos dígitos)
return date.length === 8 && /^\d+$/.test(date);
});
//console.log('Fechas válidas:', validDates);
for (const date of validDates) {
const dailyData = {
date
};
// Mantenemos los valores originales (incluyendo -999 y 0)
const processValue = (value) => {
return Number(value);
};
// Asignamos los valores correspondientes a cada parámetro
if (parameters['T2M'] && parameters['T2M'][date] !== undefined) {
dailyData.temperature = processValue(parameters['T2M'][date]);
}
if (parameters['T2M_MAX'] && parameters['T2M_MAX'][date] !== undefined) {
dailyData.maxTemperature = processValue(parameters['T2M_MAX'][date]);
}
if (parameters['T2M_MIN'] && parameters['T2M_MIN'][date] !== undefined) {
dailyData.minTemperature = processValue(parameters['T2M_MIN'][date]);
}
if (parameters['PRECTOTCORR'] && parameters['PRECTOTCORR'][date] !== undefined) {
dailyData.precipitation = processValue(parameters['PRECTOTCORR'][date]);
}
if (parameters['RH2M'] && parameters['RH2M'][date] !== undefined) {
dailyData.humidity = processValue(parameters['RH2M'][date]);
}
if (parameters['WS10M'] && parameters['WS10M'][date] !== undefined) {
dailyData.windSpeed = processValue(parameters['WS10M'][date]);
}
if (parameters['WD10M'] && parameters['WD10M'][date] !== undefined) {
dailyData.windDirection = processValue(parameters['WD10M'][date]);
}
if (parameters['PS'] && parameters['PS'][date] !== undefined) {
dailyData.pressure = processValue(parameters['PS'][date]);
}
if (parameters['CLOUD_AMT'] && parameters['CLOUD_AMT'][date] !== undefined) {
dailyData.cloudCover = processValue(parameters['CLOUD_AMT'][date]);
}
if (parameters['ALLSKY_SFC_SW_DWN'] && parameters['ALLSKY_SFC_SW_DWN'][date] !== undefined) {
dailyData.solarRadiation = processValue(parameters['ALLSKY_SFC_SW_DWN'][date]);
}
if (parameters['TSOIL1'] && parameters['TSOIL1'][date] !== undefined) {
dailyData.soilTemperature = processValue(parameters['TSOIL1'][date]);
}
if (parameters['TSOIL2'] && parameters['TSOIL2'][date] !== undefined) {
dailyData.deepSoilTemperature = processValue(parameters['TSOIL2'][date]);
}
if (parameters['GWETROOT'] && parameters['GWETROOT'][date] !== undefined) {
dailyData.rootZoneMoisture = processValue(parameters['GWETROOT'][date]);
}
if (parameters['GWETTOP'] && parameters['GWETTOP'][date] !== undefined) {
dailyData.topSoilMoisture = processValue(parameters['GWETTOP'][date]);
}
if (parameters['EVLAND'] && parameters['EVLAND'][date] !== undefined) {
dailyData.evapotranspiration = processValue(parameters['EVLAND'][date]);
}
if (parameters['ALLSKY_SFC_PAR_TOT'] && parameters['ALLSKY_SFC_PAR_TOT'][date] !== undefined) {
dailyData.parRadiation = processValue(parameters['ALLSKY_SFC_PAR_TOT'][date]);
}
if (parameters['T2MDEW'] && parameters['T2MDEW'][date] !== undefined) {
dailyData.dewPoint = processValue(parameters['T2MDEW'][date]);
}
if (parameters['T2MWET'] && parameters['T2MWET'][date] !== undefined) {
dailyData.wetBulbTemperature = processValue(parameters['T2MWET'][date]);
}
// Mantener compatibilidad con los nombres anteriores
if (parameters['T_SOIL'] && parameters['T_SOIL'][date] !== undefined) {
dailyData.soilTemperature = processValue(parameters['T_SOIL'][date]);
}
if (parameters['SOIL_M'] && parameters['SOIL_M'][date] !== undefined) {
dailyData.soilMoisture = processValue(parameters['SOIL_M'][date]);
}
if (parameters['GDD10'] && parameters['GDD10'][date] !== undefined) {
dailyData.growingDegreeDays = processValue(parameters['GDD10'][date]);
}
// Actualizar RH2M_HR
if (parameters['RH2M_HR'] && parameters['RH2M_HR'][date] !== undefined) {
dailyData.maxHumidity = processValue(parameters['RH2M_HR'][date]);
}
// Solo agregamos la entrada si tiene al menos un valor válido
const hasValidData = Object.keys(dailyData).length > 1; // Más que solo 'date'
if (hasValidData) {
results.push(dailyData);
}
}
return results;
}
/**
* Calcula índices agroclimáticos basados en datos meteorológicos
* @param data Datos meteorológicos diarios
* @returns Índices agroclimáticos
* @private
*/
calculateAgroClimateIndices(data) {
const indices = {};
// Índice de sequía (basado en precipitación y evapotranspiración)
if (data.precipitation !== undefined && data.evapotranspiration !== undefined &&
data.precipitation !== -999 && data.evapotranspiration !== -999 &&
data.evapotranspiration !== 0) {
// Relación entre precipitación y evapotranspiración
const ratio = data.precipitation / data.evapotranspiration;
indices.droughtIndex = Math.max(0, 1 - ratio); // 0 (sin sequía) a 1 (severa)
}
else {
indices.droughtIndex = 'no definido';
}
// Índice de estrés por calor
if (data.maxTemperature !== undefined && data.humidity !== undefined &&
data.maxTemperature !== -999 && data.humidity !== -999 &&
data.maxTemperature !== 0 && data.humidity !== 0) {
// Simplificación del índice de calor
const heatIndex = data.maxTemperature + (data.humidity * 0.1);
// Normalizado a una escala de 0-10
indices.heatStressIndex = Math.max(0, Math.min(10, (heatIndex - 25) / 2));
}
else {
indices.heatStressIndex = 'no definido';
}
// Riesgo de heladas (0-1 o 'no definido')
if (data.minTemperature !== undefined && data.minTemperature !== -999) {
if (data.minTemperature <= 0 && data.minTemperature !== 0) {
indices.freezeRisk = 1; // Helada confirmada
}
else if (data.minTemperature < 3) {
indices.freezeRisk = Math.max(0, (3 - data.minTemperature) / 3);
}
else {
indices.freezeRisk = 0;
}
}
else {
indices.freezeRisk = 'no definido';
}
// Riesgo de enfermedades (basado en humedad y temperatura)
if (data.humidity !== undefined && data.temperature !== undefined) {
// Las enfermedades suelen proliferar con alta humedad y temperaturas moderadas
if (data.humidity > 80 && data.temperature > 15 && data.temperature < 30) {
indices.diseaseRisk = Math.min(1, (data.humidity - 80) / 20 * ((30 - Math.abs(data.temperature - 22.5)) / 7.5));
}
else {
indices.diseaseRisk = 0;
}
}
// Necesidad de riego (mm)
if (data.evapotranspiration !== undefined && data.precipitation !== undefined && data.soilMoisture !== undefined) {
const waterDeficit = Math.max(0, data.evapotranspiration - data.precipitation);
const soilMoistureDeficit = Math.max(0, 50 - data.soilMoisture); // 50% como humedad objetivo
indices.irrigationNeed = waterDeficit + (soilMoistureDeficit * 0.5);
}
// Condiciones de siembra
if (data.soilTemperature !== undefined && data.soilMoisture !== undefined) {
// Temperatura del suelo > 10°C y humedad del suelo entre 30-70% son buenas condiciones
indices.optimalPlantingConditions = (data.soilTemperature >= 10 &&
data.soilMoisture >= 30 &&
data.soilMoisture <= 70);
}
// Condiciones de cosecha
if (data.precipitation !== undefined && data.humidity !== undefined) {
if (data.precipitation < 1 && data.humidity < 70) {
indices.harvestConditions = 'Buenas';
}
else if (data.precipitation < 5 && data.humidity < 85) {
indices.harvestConditions = 'Regulares';
}
else {
indices.harvestConditions = 'Malas';
}
}
return indices;
}
/**
* Genera recomendaciones agrícolas basadas en datos meteorológicos e índices
* @param data Datos meteorológicos diarios
* @param indices Índices agroclimáticos
* @returns Recomendaciones agrícolas
* @private
*/
generateRecommendations(data, indices) {
// Recomendaciones de riego
const irrigation = {
recommended: false,
amount: 0,
message: 'No es necesario regar hoy.'
};
if (indices.irrigationNeed && indices.irrigationNeed !== 'no definido' && indices.irrigationNeed > 3) {
irrigation.recommended = true;
irrigation.amount = Math.round(indices.irrigationNeed);
irrigation.message = `Se recomienda regar con aproximadamente ${irrigation.amount} mm de agua.`;
}
else if (indices.irrigationNeed === 'no definido') {
irrigation.message = 'No hay datos suficientes para determinar la necesidad de riego.';
}
// Recomendaciones de control de plagas
const pestControl = {
recommended: false,
riskLevel: 'bajo',
message: 'Riesgo bajo de plagas y enfermedades hoy.'
};
if (indices.diseaseRisk && typeof indices.diseaseRisk === 'number' && indices.diseaseRisk > 0.7) {
pestControl.recommended = true;
pestControl.riskLevel = 'alto';
pestControl.message = 'ALERTA: Alto riesgo de enfermedades debido a condiciones de humedad y temperatura. Considere aplicar medidas preventivas.';
}
else if (indices.diseaseRisk && typeof indices.diseaseRisk === 'number' && indices.diseaseRisk > 0.4) {
pestControl.recommended = true;
pestControl.riskLevel = 'medio';
pestControl.message = 'Riesgo moderado de enfermedades. Monitoree sus cultivos con atención.';
}
else if (indices.diseaseRisk === 'no definido') {
pestControl.riskLevel = 'no definido';
pestControl.message = 'No hay datos suficientes para evaluar el riesgo de enfermedades.';
}
// Recomendaciones de fertilización
const fertilization = {
recommended: false,
message: 'No es recomendable fertilizar hoy.'
};
// No fertilizar si hay mucha lluvia o está prevista
if ((data.precipitation || 0) < 5 && (data.soilMoisture || 0) > 20) {
fertilization.recommended = true;
fertilization.message = 'Condiciones adecuadas para la aplicación de fertilizantes.';
}
// Operaciones de campo
const fieldOperations = {
canWork: true,
message: 'Condiciones favorables para trabajar en el campo.'
};
if ((data.precipitation || 0) > 5 || (data.soilMoisture || 0) > 80) {
fieldOperations.canWork = false;
fieldOperations.message = 'Suelo demasiado húmedo para operaciones con maquinaria. Se recomienda posponer trabajos de campo.';
}
// Recomendaciones de siembra
const planting = {
recommended: indices.optimalPlantingConditions === 'no definido' ?
'no definido' :
(indices.optimalPlantingConditions || false),
message: indices.optimalPlantingConditions === 'no definido' ?
'No hay datos suficientes para evaluar condiciones de siembra.' :
(indices.optimalPlantingConditions ?
'Condiciones óptimas para siembra. Temperatura y humedad del suelo adecuadas.' :
'Condiciones no óptimas para siembra. Verifique temperatura y humedad del suelo.')
};
// Recomendaciones de cosecha
const harvesting = {
recommended: indices.harvestConditions === 'Buenas',
message: `Condiciones de cosecha: ${indices.harvestConditions || 'No disponibles'}.`
};
if (indices.harvestConditions === 'Buenas') {
harvesting.message += ' Aproveche para cosechar hoy.';
}
else if (indices.harvestConditions === 'Malas') {
harvesting.message += ' Se recomienda posponer la cosecha.';
}
return {
irrigation,
pestControl,
fertilization,
fieldOperations,
planting,
harvesting
};
}
/**
* Formatea una fecha al formato YYYYMMDD
* @param date Fecha a formatear
* @returns Fecha formateada
* @private
*/
formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}${month}${day}`;
}
}
exports.NasaPowerClient = NasaPowerClient;