138 lines
3.1 KiB
TypeScript
138 lines
3.1 KiB
TypeScript
|
|
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
|
||
|
|
}
|
||
|
|
})
|