export const spec = { openapi: '3.0.0', info: { title: 'Weather Station', version: '1.0.0', description: 'Hyperlocal weather station — sensor data, forecasts, celestial & space weather', }, servers: [{ url: 'http://localhost:3000' }], paths: { '/api/data': { get: { summary: 'Current conditions', description: 'Latest reading of all metrics — sensor, forecast, celestial & space weather merged into a single flat object', parameters: [ { name: 'fields', in: 'query', required: false, schema: { type: 'string' }, description: 'Comma-separated list of fields to return. Omit for all.' } ], responses: { 200: { description: 'Current conditions', content: { 'application/json': { schema: { $ref: '#/components/schemas/DataRow' } } } } } } }, '/api/hourly': { get: { summary: 'Hourly data', description: 'Hourly aggregated sensor data merged with Open-Meteo hourly forecast, celestial positions and space weather. Defaults to today.', parameters: [ { name: 'start', in: 'query', required: false, schema: { type: 'string', format: 'date-time' }, description: 'ISO8601 start timestamp. Defaults to today 00:00.' }, { name: 'end', in: 'query', required: false, schema: { type: 'string', format: 'date-time' }, description: 'ISO8601 end timestamp. Defaults to now.' }, { name: 'fields', in: 'query', required: false, schema: { type: 'string' }, description: 'Comma-separated list of fields to return. Omit for all.' }, ], responses: { 200: { description: 'Array of hourly rows', content: { 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/DataRow' } } } } } } } }, '/api/daily': { get: { summary: 'Daily data', description: 'Daily aggregated sensor data (mean/min/max) merged with Open-Meteo daily forecast and celestial events. Defaults to today.', parameters: [ { name: 'start', in: 'query', required: false, schema: { type: 'string', format: 'date-time' }, description: 'ISO8601 start timestamp. Defaults to today 00:00.' }, { name: 'end', in: 'query', required: false, schema: { type: 'string', format: 'date-time' }, description: 'ISO8601 end timestamp. Defaults to now.' }, { name: 'fields', in: 'query', required: false, schema: { type: 'string' }, description: 'Comma-separated list of fields to return. Omit for all.' }, ], responses: { 200: { description: 'Array of daily rows', content: { 'application/json': { schema: { type: 'array', items: { $ref: '#/components/schemas/DataRow' } } } } } } } }, }, components: { schemas: { DataRow: { type: 'object', properties: { time: { type: 'string', description: 'ISO8601 timestamp or date' }, // Environment env_temp_c: { type: 'number', description: 'Temperature (°C)' }, env_temp_f: { type: 'number', description: 'Temperature (°F)' }, env_temp_min_c: { type: 'number', description: 'Daily min temperature (°C)' }, env_temp_max_c: { type: 'number', description: 'Daily max temperature (°C)' }, env_humidity: { type: 'number', description: 'Relative humidity (%)' }, env_dew_point_c: { type: 'number', description: 'Dew point (°C)' }, env_heat_index_c: { type: 'number', description: 'Feels like / heat index (°C)' }, env_pressure_hpa: { type: 'number', description: 'Station pressure (hPa)' }, env_pressure_slp: { type: 'number', description: 'Sea level pressure (hPa)' }, env_pressure_rate: { type: 'number', description: 'Pressure change rate (hPa/hr)' }, env_pressure_trend: { type: 'string', enum: ['Rising','Falling','Stable'], description: 'Pressure trend label' }, env_abs_humidity: { type: 'number', description: 'Absolute humidity (g/m³)' }, env_vpd_kpa: { type: 'number', description: 'Vapour pressure deficit (kPa)' }, env_gas_ohms: { type: 'number', description: 'BME680 gas resistance (Ω)' }, env_aqi_score: { type: 'number', description: 'Air quality index score (0–100)' }, env_aqi_label: { type: 'string', enum: ['Excellent','Good','Fair','Poor','Very Poor'] }, env_frost_risk: { type: 'string', enum: ['None','Low','Moderate','High'] }, // Light light_lux: { type: 'number', description: 'Illuminance (lux)' }, light_uvi: { type: 'number', description: 'UV index' }, light_solar_wm2: { type: 'number', description: 'Solar irradiance (W/m²)' }, light_uv_dose_mj: { type: 'number', description: 'Accumulated UV dose today (mJ/cm²)' }, light_burn_time_min: { type: 'number', description: 'Time to sunburn skin type 2 (min)' }, light_cloud_pct: { type: 'number', description: 'Estimated cloud cover (%)' }, light_cloud_label: { type: 'string', enum: ['Clear','Partly Cloudy','Mostly Cloudy','Overcast'] }, light_dli: { type: 'number', description: 'Daily light integral (mol/m²/day)' }, light_daylight_hours: { type: 'number', description: 'Hours above daylight threshold today' }, light_visibility_km: { type: 'number', description: 'Estimated visibility (km)' }, light_uvi_max: { type: 'number', description: 'Daily max UV index' }, light_solar_wm2_sum: { type: 'number', description: 'Daily solar radiation sum (MJ/m²)' }, // Wind (Open-Meteo) wind_speed_kmh: { type: 'number', description: 'Wind speed (km/h)' }, wind_direction_deg: { type: 'number', description: 'Wind direction (°)' }, wind_gusts_kmh: { type: 'number', description: 'Wind gusts (km/h)' }, wind_speed_max_kmh: { type: 'number', description: 'Daily max wind speed (km/h)' }, wind_gusts_max_kmh: { type: 'number', description: 'Daily max wind gusts (km/h)' }, // Forecast forecast_weathercode: { type: 'number', description: 'WMO weather code' }, forecast_weather_label: { type: 'string', description: 'Human readable weather label' }, forecast_weather_icon: { type: 'string', description: 'Local icon path e.g. /icons/01d.png' }, forecast_precipitation_mm: { type: 'number', description: 'Precipitation (mm)' }, forecast_precipitation_probability: { type: 'number', description: 'Precipitation probability (%)' }, forecast_snowfall_mm: { type: 'number', description: 'Snowfall (mm)' }, forecast_snow_depth_m: { type: 'number', description: 'Snow depth (m)' }, forecast_cape: { type: 'number', description: 'Convective available potential energy (J/kg)' }, forecast_freezing_level_m: { type: 'number', description: 'Freezing level altitude (m)' }, forecast_evapotranspiration_mm:{ type: 'number', description: 'Evapotranspiration (mm)' }, // Seismic seismic_ax: { type: 'number', description: 'Peak acceleration X axis (g)' }, seismic_ay: { type: 'number', description: 'Peak acceleration Y axis (g)' }, seismic_az: { type: 'number', description: 'Peak acceleration Z axis (g, includes gravity)' }, seismic_magnitude: { type: 'number', description: 'Peak seismic magnitude (g, gravity removed)' }, // Compass compass_heading: { type: 'number', description: 'Magnetic heading (°)' }, compass_x: { type: 'number' }, compass_y: { type: 'number' }, compass_z: { type: 'number' }, // Ground / Accumulation ground_distance_cm: { type: 'number', description: 'LIDAR ground distance (cm)' }, ground_lidar_strength: { type: 'number', description: 'LIDAR signal strength' }, ground_calibrated_baseline_cm: { type: 'number', description: 'Calibrated baseline distance (cm)' }, ground_accumulation_depth_cm: { type: 'number', description: 'Snow/flood depth (cm)' }, ground_accumulation_type: { type: 'string', enum: ['snow','slush','ice','flood'], description: 'Accumulation type' }, // Lightning lightning_distance_km: { type: 'number', description: 'Lightning strike distance (km)' }, lightning_energy: { type: 'number', description: 'Lightning energy' }, lightning_strikes_per_hour: { type: 'number', description: 'Strike rate (strikes/hr)' }, lightning_storm_trend: { type: 'string', enum: ['Approaching','Retreating','Stationary'] }, lightning_false_positive: { type: 'number', description: '1 if disturber/false positive' }, lightning_detector_sensitivity:{ type: 'number', description: 'AS3935 noise floor setting (0–7)' }, // GPS gps_lat: { type: 'number', description: 'Latitude (°)' }, gps_lon: { type: 'number', description: 'Longitude (°)' }, gps_alt_m: { type: 'number', description: 'Altitude (m)' }, gps_satellites: { type: 'number', description: 'Satellites in view' }, gps_speed_kmh: { type: 'number', description: 'Ground speed (km/h)' }, gps_heading: { type: 'number', description: 'GPS heading (°)' }, // Sun sun_elevation: { type: 'number', description: 'Solar elevation angle (°)' }, sun_azimuth: { type: 'number', description: 'Solar azimuth (°)' }, sun_sunrise: { type: 'string', description: 'Sunrise time (ISO8601)' }, sun_sunset: { type: 'string', description: 'Sunset time (ISO8601)' }, sun_solar_noon: { type: 'string', description: 'Solar noon (ISO8601)' }, sun_day_length_hours: { type: 'number', description: 'Day length (hours)' }, sun_golden_hour_morning_start: { type: 'string' }, sun_golden_hour_morning_end: { type: 'string' }, sun_golden_hour_evening_start: { type: 'string' }, sun_golden_hour_evening_end: { type: 'string' }, sun_is_day: { type: 'number', description: '1 if daytime' }, sun_ssn: { type: 'number', description: 'Estimated sunspot number' }, sun_activity_label: { type: 'string', enum: ['Very Low','Low','Moderate','High','Very High'] }, // Moon moon_phase: { type: 'string', description: 'Moon phase name' }, moon_illumination_pct: { type: 'number', description: 'Moon illumination (%)' }, moon_moonrise: { type: 'string', description: 'Moonrise time (ISO8601)' }, moon_moonset: { type: 'string', description: 'Moonset time (ISO8601)' }, moon_next_full: { type: 'string', description: 'Next full moon (ISO8601)' }, moon_next_new: { type: 'string', description: 'Next new moon (ISO8601)' }, // Season season_next_event: { type: 'string', description: 'Next solstice/equinox name' }, season_next_event_date: { type: 'string' }, season_last_event: { type: 'string' }, season_last_event_date: { type: 'string' }, // Space weather space_kp_index: { type: 'number', description: 'Planetary K index (0–9)' }, space_ap_index: { type: 'number', description: 'Ap geomagnetic index' }, space_geomagnetic_storm: { type: 'string', enum: ['None','Minor','Moderate','Strong','Severe'] }, space_solar_wind_speed_kms: { type: 'number', description: 'Solar wind speed (km/s)' }, space_solar_wind_density: { type: 'number', description: 'Solar wind proton density (p/cm³)' }, space_solar_wind_temp: { type: 'number', description: 'Solar wind temperature (K)' }, space_imf_bz: { type: 'number', description: 'IMF Bz component (nT)' }, space_imf_bt: { type: 'number', description: 'IMF total field Bt (nT)' }, space_solar_flux_f107: { type: 'number', description: 'Solar flux F10.7 index' }, // Marine wave_height: { type: 'number', description: 'Significant wave height (m)' }, wave_direction: { type: 'number', description: 'Wave direction (°)' }, wave_period: { type: 'number', description: 'Wave period (s)' }, swell_wave_height: { type: 'number', description: 'Swell wave height (m)' }, swell_wave_direction: { type: 'number', description: 'Swell direction (°)' }, swell_wave_period: { type: 'number', description: 'Swell period (s)' }, wind_wave_height: { type: 'number', description: 'Wind wave height (m)' }, wave_height_max: { type: 'number', description: 'Daily max wave height (m)' }, // AQ pm10: { type: 'number', description: 'PM10 (μg/m³)' }, pm2_5: { type: 'number', description: 'PM2.5 (μg/m³)' }, carbon_monoxide: { type: 'number', description: 'CO (μg/m³)' }, nitrogen_dioxide: { type: 'number', description: 'NO₂ (μg/m³)' }, sulphur_dioxide: { type: 'number', description: 'SO₂ (μg/m³)' }, ozone: { type: 'number', description: 'O₃ (μg/m³)' }, aerosol_optical_depth: { type: 'number' }, dust: { type: 'number', description: 'Dust (μg/m³)' }, alder_pollen: { type: 'number', description: 'Alder pollen (grains/m³)' }, birch_pollen: { type: 'number', description: 'Birch pollen (grains/m³)' }, grass_pollen: { type: 'number', description: 'Grass pollen (grains/m³)' }, mugwort_pollen: { type: 'number', description: 'Mugwort pollen (grains/m³)' }, olive_pollen: { type: 'number', description: 'Olive pollen (grains/m³)' }, ragweed_pollen: { type: 'number', description: 'Ragweed pollen (grains/m³)' }, } } } } }