summaryrefslogtreecommitdiffstats
path: root/converter.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--converter.go138
1 files changed, 138 insertions, 0 deletions
diff --git a/converter.go b/converter.go
new file mode 100644
index 0000000..0e2b74c
--- /dev/null
+++ b/converter.go
@@ -0,0 +1,138 @@
+// converter.go - Converts ForecastData to OWMResponse
+package main
+
+import (
+ "fmt"
+ "math"
+ "time"
+)
+
+// ToOWMResponse converts ForecastData to OWMResponse format
+func (fd *ForecastData) ToOWMResponse(mapper *WeatherMapper) (*OWMResponse, error) {
+ loc, err := time.LoadLocation(fd.Timezone)
+ if err != nil {
+ return nil, fmt.Errorf("loading timezone: %w", err)
+ }
+
+ // Calculate timezone offset
+ firstTime := time.Unix(fd.Timestamps[0], 0).UTC()
+ _, offset := firstTime.In(loc).Zone()
+
+ // Create response
+ response := &OWMResponse{
+ Lat: fd.Latitude,
+ Lon: fd.Longitude,
+ Timezone: fd.Timezone,
+ TimezoneOffset: offset,
+ }
+
+ // Calculate sunrise/sunset for first day
+ sunCalc := NewSunCalculator(fd.Latitude, fd.Longitude, float64(offset)/3600)
+ sunrise, sunset, err := sunCalc.Calculate(firstTime)
+ if err != nil {
+ // Use defaults if calculation fails
+ sunrise = firstTime.Add(8 * time.Hour)
+ sunset = firstTime.Add(16 * time.Hour)
+ }
+
+ // Convert each forecast point
+ hourly := make([]Current, 0, len(fd.Timestamps))
+ for i, timestamp := range fd.Timestamps {
+ current, err := fd.convertToCurrent(i, timestamp, loc, sunrise, sunset, mapper)
+ if err != nil {
+ return nil, fmt.Errorf("converting point %d: %w", i, err)
+ }
+ hourly = append(hourly, current)
+ }
+
+ response.Current = hourly[0]
+ response.Current.Sunrise = sunrise.Unix()
+ response.Current.Sunset = sunset.Unix()
+ response.Hourly = hourly
+
+ return response, nil
+}
+
+func (fd *ForecastData) convertToCurrent(index int, timestamp int64, loc *time.Location, sunrise, sunset time.Time, mapper *WeatherMapper) (Current, error) {
+ current := Current{
+ Dt: timestamp,
+ Uvi: 0, // Not available from FMI
+ }
+
+ // Add ISO 8601 local time
+ current.LocalTime = time.Unix(timestamp, 0).In(loc).Format(time.RFC3339)
+
+ // Extract temperature
+ if val, err := fd.getFloatValue(index, "Temperature"); err == nil && !math.IsNaN(val) {
+ current.Temp = val
+ }
+
+ // Extract humidity
+ if val, err := fd.getFloatValue(index, "Humidity"); err == nil && !math.IsNaN(val) {
+ current.Humidity = int(math.Round(val))
+ }
+
+ // Extract pressure
+ if val, err := fd.getFloatValue(index, "Pressure"); err == nil && !math.IsNaN(val) {
+ current.Pressure = int(math.Round(val))
+ }
+
+ // Extract dew point
+ if val, err := fd.getFloatValue(index, "dewPoint"); err == nil && !math.IsNaN(val) {
+ current.DewPoint = val
+ }
+
+ // Extract wind speed
+ if val, err := fd.getFloatValue(index, "WindSpeedMS"); err == nil && !math.IsNaN(val) {
+ current.WindSpeed = val
+ }
+
+ // Extract wind direction
+ if val, err := fd.getFloatValue(index, "WindDirection"); err == nil && !math.IsNaN(val) {
+ current.WindDeg = int(math.Round(val))
+ }
+
+ // Extract wind gust
+ if val, err := fd.getFloatValue(index, "WindGust"); err == nil && !math.IsNaN(val) {
+ current.WindGust = val
+ }
+
+ // Extract cloud cover
+ if val, err := fd.getFloatValue(index, "TotalCloudCover"); err == nil && !math.IsNaN(val) {
+ current.Clouds = int(math.Round(val))
+ }
+
+ // Extract visibility
+ if val, err := fd.getFloatValue(index, "visibility"); err == nil && !math.IsNaN(val) {
+ current.Visibility = int(math.Round(val))
+ }
+
+ // Calculate feels-like temperature
+ current.FeelsLike = CalculateFeelsLike(current.Temp, float64(current.Humidity), current.WindSpeed)
+
+ // Handle precipitation
+ if val, err := fd.getFloatValue(index, "PrecipitationRate"); err == nil && !math.IsNaN(val) && val > 0 {
+ current.Rain = &Rain{OneH: val}
+ }
+
+ // Map weather symbol
+ if val, err := fd.getFloatValue(index, "WeatherSymbol3"); err == nil && !math.IsNaN(val) {
+ symbol := int(math.Round(val))
+ forecastTime := time.Unix(timestamp, 0)
+ current.Weather = []Weather{mapper.Map(symbol, forecastTime, sunrise, sunset)}
+ } else {
+ // Default weather
+ current.Weather = []Weather{{800, "Clear", "clear sky", "01d"}}
+ }
+
+ return current, nil
+}
+
+func (fd *ForecastData) getFloatValue(rowIndex int, paramName string) (float64, error) {
+ if paramIndex, ok := fd.ParamIndex[paramName]; ok {
+ if rowIndex < len(fd.Values) && paramIndex < len(fd.Values[rowIndex]) {
+ return fd.Values[rowIndex][paramIndex], nil
+ }
+ }
+ return math.NaN(), fmt.Errorf("parameter %s not found or out of bounds", paramName)
+}