diff --git a/fetcher/index.js b/fetcher/index.js index b5bccd5..a810aba 100644 --- a/fetcher/index.js +++ b/fetcher/index.js @@ -13,30 +13,48 @@ const lat = 51.58; const lon = -4.29; const marineUrl = `https://marine-api.open-meteo.com/v1/marine?latitude=${lat}&longitude=${lon}¤t=swell_wave_height,swell_wave_period,swell_wave_direction,wind_wave_height`; const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}¤t=wind_speed_10m,wind_direction_10m`; +const tideUrl = `https://flood-api.open-meteo.com/v1/flood?latitude=${lat}&longitude=${lon}&daily=sealevel_max,sealevel_min&hourly=sealevel`; async function fetchSurfData() { try { - const [marineRes, weatherRes] = await Promise.all([ + const [marineRes, weatherRes, tideRes] = await Promise.all([ axios.get(marineUrl), - axios.get(weatherUrl) + axios.get(weatherUrl), + axios.get(tideUrl) ]); - const currentSwell = marineRes.data.current; - const currentWind = weatherRes.data.current; + const beachTime = new Intl.DateTimeFormat('en-GB', { + hour: 'numeric', + hour12: false, + timeZone: 'Europe/London' + }).format(new Date()); + const currentHour = parseInt(beachTime); + const hourlyData = tideRes.data.hourly.sealevel; + const currentTideHeight = hourlyData[currentHour]; + const nextHour = (currentHour + 1) % hourlyData.length; + const nextTideHeight = hourlyData[nextHour]; + const isPushing = nextTideHeight > currentTideHeight; + const tideDirection = isPushing ? "Pushing" : "Pulling"; + const swell = marineRes.data.current; + const wind = weatherRes.data.current; + const finalScore = getSurfScore(swell, wind, isPushing); + const point = new Point('surf_conditions') - .tag('location', 'rhossili_beach') - .floatField('swell_height', currentSwell.swell_wave_height) - .floatField('swell_period', currentSwell.swell_wave_period) - .floatField('swell_direction', currentSwell.swell_wave_direction) - .floatField('wind_speed', currentWind.wind_speed_10m) - .floatField('wind_direction', currentWind.wind_direction_10m); + .tag('location', 'llangennith_beach') + .tag('tide_direction', tideDirection) + .floatField('tide_height', currentTideHeight) + .floatField('swell_height', swell.swell_wave_height) + .floatField('swell_period', swell.swell_wave_period) + .floatField('swell_direction', swell.swell_wave_direction) + .floatField('wind_speed', wind.wind_speed_10m) + .floatField('wind_direction', wind.wind_direction_10m) + .intField('surf_score', finalScore); writeApi.writePoint(point); await writeApi.flush(); - console.log(`✅ Success: Captured ${currentSwell.swell_wave_height}m swell and ${currentWind.wind_speed_10m}km/h wind.`); + console.log(`📡 Score: ${finalScore}/10 | Tide: ${tideDirection} | Period: ${swell.swell_wave_period}s`); } catch (error) { - // If it's a connection error, let's be descriptive if (error.code === 'ECONNREFUSED') { console.error("❌ Database is not ready yet. Retrying in the next cycle..."); } else { @@ -45,9 +63,28 @@ async function fetchSurfData() { } } -// 10 second delay for the very first run to let InfluxDB boot up +function getSurfScore(swell, wind, isPushing){ + let score = 5; + + if (swell.swell_wave_height < 0.5) { + score = 1; + } else { + if (swell.swell_wave_period >= 9 && swell.swell_wave_period <= 13) score += 2; + else if (swell.swell_wave_period > 13) score += 1; + else if (swell.swell_wave_period < 7) score -= 2; + + const isOffshore = wind.wind_direction_10m >= 70 && wind.wind_direction_10m <= 110; + const isOnshore = wind.wind_direction_10m > 190 || wind.wind_direction_10m < 20; + + if (isOffshore) score += 3; + else if (isOnshore && wind.wind_speed_10m > 12) score -= 4; + + if (isPushing) score += 1; + } + return Math.max(1, Math.min(10, score)); +} + console.log("⏳ Fetcher started. Waiting 10s for DB initialization..."); setTimeout(fetchSurfData, 10000); -// Then run every hour setInterval(fetchSurfData, 1000 * 60 * 60); \ No newline at end of file