Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/environment

src/aqi.ts

63 lines · 1.6 KB · TypeScript
import airQualityLookup from './air-quality.ts'

export type AirQualityLookupParams = {
	location?: string
	latitude?: number
	longitude?: number
	label?: string
	date?: string
	hour?: number | null
	hourlyLimit?: number
}

export type AirQualitySummary = {
	location: string
	date: string
	usAqi: number | null
	category: string
	europeanAqi: number | null
	pm25: number | null
	pm10: number | null
	peakHour: string | null
	summary: string
}

function requirePlace(params: AirQualityLookupParams = {}) {
	const input = typeof params === 'object' && params ? params : {}
	const hasCoords =
		input.latitude !== undefined &&
		input.latitude !== null &&
		input.longitude !== undefined &&
		input.longitude !== null
	const hasLocation = Boolean(String(input.location || '').trim())
	if (!hasCoords && !hasLocation) {
		throw new Error(
			'Provide either a location string or latitude and longitude.',
		)
	}
	return input
}

/** Full Open-Meteo air-quality lookup for a location or coordinates. */
export async function getAirQuality(params: AirQualityLookupParams = {}) {
	return airQualityLookup(requirePlace(params))
}

/** Compact AQI summary for briefings and automations. */
export async function summarizeAirQuality(
	params: AirQualityLookupParams = {},
) {
	const result = await airQualityLookup(requirePlace(params))

	return {
		location: result.location.displayName,
		date: result.date,
		usAqi: result.daily.maxUsAqi,
		category: result.daily.maxUsCategory,
		europeanAqi: result.daily.maxEuropeanAqi,
		pm25: result.daily.avgPm25,
		pm10: result.daily.avgPm10,
		peakHour: result.daily.peakHour?.time ?? null,
		summary: result.summary,
	} satisfies AirQualitySummary
}