dow/server/src/app/services/weather.ts

138 lines
3.1 KiB
TypeScript
Raw Normal View History

2024-06-02 15:40:04 +02:00
import { service } from '../service'
import { ForecastData, TimeseriesData } from './weather/types'
type WeatherItem = DetailedWeatherItem | SummaryWeatherItem
interface SummaryWeatherItem {
date: string
temperature: { min: number; max: number }
summary: null | string
precipitationAmount: number
}
interface DetailedWeatherItem {
date: string
summary: null | string
precipitationAmount: null | number
temperature: number
windDirection: number
windSpeed: number
relativeHumidity: number
airPressure: number
}
const API_URL = 'https://api.met.no/weatherapi'
const API_USER_AGENT = 'KamenWatch 1.0 jan@zipek.cz'
const API_PARAMS = {
lat: '50.070219',
lon: '14.414034',
}
const getSummaryItem = (date: string, item: TimeseriesData) => {
if (item.next_6_hours) {
return {
date,
temperature: {
min: item.next_6_hours.details.air_temperature_min,
max: item.next_6_hours.details.air_temperature_max,
},
summary: item.next_6_hours.summary.symbol_code,
precipitationAmount: item.next_6_hours.details.precipitation_amount,
} as SummaryWeatherItem
}
}
const getDetailedItem = (date: string, item: TimeseriesData) => {
const detail = item.instant?.details
if (!detail) {
return
}
const result: DetailedWeatherItem = {
date,
temperature: detail.air_temperature,
airPressure: detail.air_pressure_at_sea_level,
relativeHumidity: detail.relative_humidity,
windDirection: detail.wind_from_direction,
windSpeed: detail.wind_speed,
precipitationAmount: null,
summary: null,
}
if (item.next_1_hours) {
result.summary = item.next_1_hours.summary.symbol_code
result.precipitationAmount = item.next_1_hours.details.precipitation_amount
} else if (item.next_6_hours) {
result.summary = item.next_6_hours.summary.symbol_code
} else if (item.next_12_hours) {
result.summary = item.next_12_hours.summary.symbol_code
}
return result
}
export const weatherService = service(({ fetch }) => {
return async () => {
const forecast: ForecastData = JSON.parse(
await fetch(
`${API_URL}/locationforecast/2.0/complete?lat=${API_PARAMS.lat}&lon=${API_PARAMS.lon}`,
{
headers: {
'User-agent': API_USER_AGENT,
},
},
),
)
const result = {
now: null as WeatherItem | null,
hours: {} as Record<number, WeatherItem>,
days: {} as Record<number, WeatherItem>,
}
let recordedHours = 0
const nowDays = Math.floor(Date.now() / 1000 / 3600 / 24)
const nowHours = Math.floor(Date.now() / 1000 / 3600)
forecast.properties.timeseries.forEach((item, index) => {
const date = new Date(item['time'])
const converted = getDetailedItem(item.time, item.data)
if (!converted) {
return
}
if (index === 0) {
result.now = converted
}
if (date.getHours() === 14) {
const dayData = getSummaryItem(item.time, item.data)
if (dayData) {
const daysDiff =
Math.floor(date.getTime() / 1000 / 3600 / 24) - nowDays
result.days[daysDiff] = dayData
}
}
if (recordedHours < 23) {
const hoursDiff = Math.floor(date.getTime() / 1000 / 3600) - nowHours
result.hours[hoursDiff] = converted
recordedHours += 1
}
})
return result
}
})