// observation.go presents observation payloads in metric and US shapes. // Layer: adapters/inbound/httpapi/presenter observation payload mapping. package presenter import ( "time" "gitea.maximumdirect.net/ejr/weatherfeeder/model" ) // WeatherObservationUS is the US-customary response shape for observations. type WeatherObservationUS struct { StationID string `json:"stationId,omitempty" xml:"stationId,omitempty"` StationName string `json:"stationName,omitempty" xml:"stationName,omitempty"` Timestamp time.Time `json:"timestamp" xml:"timestamp"` ConditionCode model.WMOCode `json:"conditionCode" xml:"conditionCode"` IsDay *bool `json:"isDay,omitempty" xml:"isDay,omitempty"` TextDescription string `json:"textDescription,omitempty" xml:"textDescription,omitempty"` TemperatureF *float64 `json:"temperatureF,omitempty" xml:"temperatureF,omitempty"` DewpointF *float64 `json:"dewpointF,omitempty" xml:"dewpointF,omitempty"` WindDirectionDegrees *float64 `json:"windDirectionDegrees,omitempty" xml:"windDirectionDegrees,omitempty"` WindSpeedMph *float64 `json:"windSpeedMph,omitempty" xml:"windSpeedMph,omitempty"` WindGustMph *float64 `json:"windGustMph,omitempty" xml:"windGustMph,omitempty"` BarometricPressureInHg *float64 `json:"barometricPressureInHg,omitempty" xml:"barometricPressureInHg,omitempty"` VisibilityMiles *float64 `json:"visibilityMiles,omitempty" xml:"visibilityMiles,omitempty"` RelativeHumidityPercent *float64 `json:"relativeHumidityPercent,omitempty" xml:"relativeHumidityPercent,omitempty"` ApparentTemperatureF *float64 `json:"apparentTemperatureF,omitempty" xml:"apparentTemperatureF,omitempty"` PresentWeather []model.PresentWeather `json:"presentWeather,omitempty" xml:"presentWeather,omitempty"` } func ObservationPayload(obs *model.WeatherObservation, units Units, precision int) any { if obs == nil { return nil } if units == UnitsUS { converted := WeatherObservationUS{ StationID: obs.StationID, StationName: obs.StationName, Timestamp: obs.Timestamp, ConditionCode: obs.ConditionCode, IsDay: copyBoolPtr(obs.IsDay), TextDescription: obs.TextDescription, TemperatureF: roundedPtr(celsiusToFahrenheitPtr(obs.TemperatureC), precision), DewpointF: roundedPtr(celsiusToFahrenheitPtr(obs.DewpointC), precision), WindDirectionDegrees: roundedPtr(copyFloat64Ptr(obs.WindDirectionDegrees), precision), WindSpeedMph: roundedPtr(scalePtr(obs.WindSpeedKmh, kmhToMphFactor), precision), WindGustMph: roundedPtr(scalePtr(obs.WindGustKmh, kmhToMphFactor), precision), BarometricPressureInHg: roundedPtr(scalePtr(obs.BarometricPressurePa, paToInHgFactor), precision), VisibilityMiles: roundedPtr(scalePtr(obs.VisibilityMeters, metersToMilesFactor), precision), RelativeHumidityPercent: roundedPtr(copyFloat64Ptr(obs.RelativeHumidityPercent), precision), ApparentTemperatureF: roundedPtr(celsiusToFahrenheitPtr(obs.ApparentTemperatureC), precision), PresentWeather: append([]model.PresentWeather(nil), obs.PresentWeather...), } return converted } rounded := model.WeatherObservation{ StationID: obs.StationID, StationName: obs.StationName, Timestamp: obs.Timestamp, ConditionCode: obs.ConditionCode, IsDay: copyBoolPtr(obs.IsDay), TextDescription: obs.TextDescription, TemperatureC: roundedPtr(copyFloat64Ptr(obs.TemperatureC), precision), DewpointC: roundedPtr(copyFloat64Ptr(obs.DewpointC), precision), WindDirectionDegrees: roundedPtr(copyFloat64Ptr(obs.WindDirectionDegrees), precision), WindSpeedKmh: roundedPtr(copyFloat64Ptr(obs.WindSpeedKmh), precision), WindGustKmh: roundedPtr(copyFloat64Ptr(obs.WindGustKmh), precision), BarometricPressurePa: roundedPtr(copyFloat64Ptr(obs.BarometricPressurePa), precision), VisibilityMeters: roundedPtr(copyFloat64Ptr(obs.VisibilityMeters), precision), RelativeHumidityPercent: roundedPtr(copyFloat64Ptr(obs.RelativeHumidityPercent), precision), ApparentTemperatureC: roundedPtr(copyFloat64Ptr(obs.ApparentTemperatureC), precision), PresentWeather: append([]model.PresentWeather(nil), obs.PresentWeather...), } return &rounded }