Files
signalk-plugin/plugin/api_models/openmeteo.js
2026-03-11 15:25:03 +01:00

246 lines
7.9 KiB
JavaScript

const axios = require('axios');
const TIMEOUT = 10000;
const HEADERS = { Accept: "application/json, text/plain;q=0.9,*/*;q=0.8" };
// Parametri API
const FORECAST_PARAMS = {
current: [
'temperature_2m',
'wind_speed_10m',
'wind_direction_10m',
'wind_gusts_10m',
'precipitation',
'rain',
'relative_humidity_2m',
'pressure_msl'
],
hourly: [
'temperature_2m',
'precipitation_probability',
'precipitation',
'rain',
'wind_speed_10m',
'cloud_cover',
'wind_direction_10m',
'relative_humidity_2m',
'pressure_msl'
]
};
const MARINE_PARAMS = {
current: [
'wave_height',
'wave_direction',
'wave_period',
'wave_peak_period',
'ocean_current_velocity',
'ocean_current_direction'
],
hourly: [
'wave_height',
'wave_direction',
'wave_period',
'wave_peak_period',
'ocean_current_velocity',
'ocean_current_direction'
]
};
// Unità di misura globali (aggiornate da OpenMeteo)
let globalUnits = {
forecast: {
temperature: '°C',
humidity: '%',
pressure: 'hPa',
windSpeed: 'km/h',
windDirection: '°',
windGusts: 'km/h',
rain: 'mm',
precipitation: 'mm'
},
waves: {
waveHeight: 'm',
wavePeriod: 's',
waveDirection: '°',
wavePeakPeriod: 's'
}
};
/**
* Ottiene le unità di misura globali
*/
function getUnits() {
return globalUnits;
}
/**
* Formatta un valore con la sua unità
*/
function formatWithUnit(value, unitKey, category = 'forecast') {
if (value === null || value === undefined) return 'n/d';
const unit = globalUnits[category]?.[unitKey] || '';
return `${value}${unit}`;
}
async function getForecast(location, options = { mode: 'both' }) {
const mode = options.mode || 'both';
const params = [];
const currentParams = FORECAST_PARAMS.current.join(",");
const hourlyParams = FORECAST_PARAMS.hourly.join(",");
if (mode === 'both' || mode === 'current') {
params.push('current=' + currentParams);
}
if (mode === 'both' || mode === 'hourly') {
params.push('hourly=' + hourlyParams);
}
if (!location?.latitude || !location?.longitude) {
console.warn('[OpenMeteo] Coordinate non valide per forecast');
return null;
}
const api = `https://api.open-meteo.com/v1/forecast?latitude=${location.latitude}&longitude=${location.longitude}&${params.join('&')}`;
try {
const response = await axios.get(api, {
headers: HEADERS,
timeout: TIMEOUT,
validateStatus: (status) => status === 200
});
const { data } = response;
// Aggiorna unità globali da API response
if (data.current_units) {
globalUnits.forecast = {
temperature: data.current_units.temperature_2m || '°C',
humidity: data.current_units.relative_humidity_2m || '%',
pressure: data.current_units.pressure_msl || 'hPa',
windSpeed: data.current_units.wind_speed_10m || 'km/h',
windDirection: data.current_units.wind_direction_10m || '°',
windGusts: data.current_units.wind_gusts_10m || 'km/h',
rain: data.current_units.rain || 'mm',
precipitation: data.current_units.precipitation || 'mm'
};
}
return {
timestamp: Date.now(),
temperature: data.current?.temperature_2m ?? null,
humidity: data.current?.relative_humidity_2m ?? null,
pressure: data.current?.pressure_msl ?? null,
// Refactored to match sensorsReferences.json hierarchy
wind: {
speed: data.current?.wind_speed_10m ?? null,
direction: data.current?.wind_direction_10m ?? null,
gusts: data.current?.wind_gusts_10m ?? null,
},
rain: data.current?.rain ?? null,
precipitation: data.current?.precipitation ?? null, // Keeping simple properties flat
// Unita di misura
units: globalUnits.forecast,
// Parametri orari
hourly: data.hourly ? {
time: data.hourly?.time,
temperature: data.hourly?.temperature_2m,
pressure: data.hourly?.pressure_msl,
precipitationProbability: data.hourly?.precipitation_probability,
precipitation: data.hourly?.precipitation,
rain: data.hourly?.rain,
cloudCover: data.hourly?.cloud_cover,
windDirection: data.hourly?.wind_direction_10m,
humidity: data.hourly?.relative_humidity_2m,
windSpeed: data.hourly?.wind_speed_10m
} : null,
hourlyUnits: data.hourly_units || null
};
} catch (error) {
console.error(`[OpenMeteo Forecast] Errore: ${error.message}`);
return null;
}
}
async function getSeaConditions(location, options = { mode: 'both' }) {
const mode = options.mode || 'both';
const params = [];
const currentParams = MARINE_PARAMS.current.join(",");
const hourlyParams = MARINE_PARAMS.hourly.join(",");
if (mode === 'both' || mode === 'current') {
params.push('current=' + currentParams);
}
if (mode === 'both' || mode === 'hourly') {
params.push('hourly=' + hourlyParams);
}
if (!location?.latitude || !location?.longitude) {
console.warn('[OpenMeteo] Coordinate non valide per onde');
return null;
}
const api = `https://marine-api.open-meteo.com/v1/marine?latitude=${location.latitude}&longitude=${location.longitude}&${params.join('&')}&models=ecmwf_wam`;
try {
const response = await axios.get(api, {
headers: HEADERS,
timeout: TIMEOUT,
validateStatus: (status) => status === 200
});
const { data } = response;
// Aggiorna unità globali da API response
if (data.current_units) {
globalUnits.waves = {
waveHeight: data.current_units.wave_height || 'm',
wavePeriod: data.current_units.wave_period || 's',
waveDirection: data.current_units.wave_direction || '°',
wavePeakPeriod: data.current_units.wave_peak_period || 's',
currentVelocity: data.current_units.ocean_current_velocity || 'm/s',
currentDirection: data.current_units.ocean_current_direction || '°'
};
}
return {
// Refactored to match sensorsReferences.json hierarchy
waves: {
height: data.current?.wave_height ?? null,
period: data.current?.wave_period ?? null,
direction: data.current?.wave_direction ?? null,
peakPeriod: data.current?.wave_peak_period ?? null
},
// Keeping these flat essentially
currentDirection: data.current?.ocean_current_direction ?? null,
currentVelocity: data.current?.ocean_current_velocity ?? null,
// Unità di misura
units: globalUnits.waves,
// Dati orari per grafici
hourly: data.hourly ? {
time: data.hourly?.time,
waveHeight: data.hourly?.wave_height,
wavePeriod: data.hourly?.wave_period,
waveDirection: data.hourly?.wave_direction,
currentDirection: data.hourly?.ocean_current_direction,
currentVelocity: data.hourly?.ocean_current_velocity
} : null,
hourlyUnits: data.hourly_units || null
};
} catch (error) {
console.error(`[OpenMeteo Marine] Errore: ${error.message}`);
return null;
}
}
module.exports = { getSeaConditions, getForecast, getUnits, formatWithUnit };