package weather import ( "math" "net/url" "strconv" ) // Attempts to complete missing fields that may not // be set by a specific provider, such as DewPoint and WindChill func (u *WeatherUpdate) Enrich() { if u == nil { return } if u.WindChillF == nil && u.TempOutdoorF != nil && u.WindSpeedMPH != nil { wc := CalculateWindChill(*u.TempOutdoorF, *u.WindSpeedMPH) u.WindChillF = &wc } if u.DewPointF == nil && (u.TempOutdoorF != nil && u.HumidityOudoor != nil) { if *u.TempOutdoorF != 0 || *u.HumidityOudoor != 0 { dp := CalculateDewPoint(*u.TempOutdoorF, float64(*u.HumidityOudoor)) u.DewPointF = &dp } } if u.BaromAbsoluteIn == nil && u.BaromRelativeIn != nil { u.BaromAbsoluteIn = u.BaromRelativeIn } } func CalculateDewPoint(tempF, humidity float64) float64 { // Convert temperature from Fahrenheit to Celsius tempC := (tempF - 32) * 5 / 9 // Calculate the dew point using the Magnus-Tetens approximation a := float64(17.27) b := float64(237.7) alpha := (a*tempC)/(b+tempC) + math.Log(humidity/100) dewPointC := (b * alpha) / (a - alpha) // Convert dew point back to Fahrenheit dewPointF := (dewPointC * 9 / 5) + 32 return dewPointF } func CalculateWindChill(tempF float64, windSpeedMPH float64) float64 { if windSpeedMPH <= 3 { // Wind chill calculation doesn't apply for very low wind speeds return tempF } // Formula for calculating wind chill return 35.74 + 0.6215*tempF - 35.75*math.Pow(windSpeedMPH, 0.16) + 0.4275*tempF*math.Pow(windSpeedMPH, 0.16) } // Helper function to set values from fields // typically from a WeatherUpdate func SetURLVal(vals *url.Values, key string, value any) { if value == nil { return } switch v := value.(type) { case *float64: if v == nil { return } str := strconv.FormatFloat(*v, 'f', 4, 64) vals.Set(key, str) case *int: if v == nil { return } str := strconv.FormatInt(int64(*v), 10) vals.Set(key, str) case *string: if v == nil { return } vals.Set(key, *v) } }