package model import "time" type WeatherObservation struct { // Identity / metadata StationID string StationName string Timestamp time.Time // Canonical internal representation (provider-independent). // // ConditionCode should be populated by all sources. ConditionText should be the // canonical human-readable string derived from the WMO code (not the provider's // original wording). // // IsDay is optional; some providers supply a day/night flag (e.g., Open-Meteo), // while others may not (e.g., NWS observations). When unknown, it can be nil. ConditionCode WMOCode ConditionText string IsDay *bool // Provider-specific “evidence” for troubleshooting mapping and drift. // // This is intentionally limited: it is not intended to be used downstream for // business logic. Downstream logic should rely on ConditionCode / ConditionText. ProviderRawDescription string // Human-facing (legacy / transitional) // // TextDescription currently carries provider text in existing drivers. // As we transition to WMO-based normalization, downstream presentation should // switch to using ConditionText. After migration, this may be removed or repurposed. TextDescription string // Provider-specific (legacy / transitional) // // IconURL is not part of the canonical internal vocabulary. It's retained only // because current sources populate it; it is not required for downstream systems. IconURL string // Core measurements (nullable) TemperatureC *float64 DewpointC *float64 WindDirectionDegrees *float64 WindSpeedKmh *float64 WindGustKmh *float64 BarometricPressurePa *float64 SeaLevelPressurePa *float64 VisibilityMeters *float64 RelativeHumidityPercent *float64 WindChillC *float64 HeatIndexC *float64 ElevationMeters *float64 RawMessage string PresentWeather []PresentWeather CloudLayers []CloudLayer } type CloudLayer struct { BaseMeters *float64 Amount string } type PresentWeather struct { Raw map[string]any }