Files
weatherreporter/internal/briefing/precip_timing_module.go

110 lines
4.3 KiB
Go

package briefing
import (
"fmt"
"strings"
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
)
const (
precipTimingChanceLowerBound = 40
precipTimingLikelyLowerBound = 50
precipTimingExpectLowerBound = 70
)
type PrecipTimingModule struct {
MaxPopPercent *int `json:"max_pop_percent,omitempty"`
MaxPopTime string `json:"max_pop_time,omitempty"`
ProbabilityThreshold float64 `json:"probability_threshold"`
PrecipitationWindows []PrecipitationWindowModule `json:"precipitation_windows,omitempty"`
ThunderMentioned bool `json:"thunder_mentioned"`
}
type PrecipitationWindowModule struct {
PeriodBegins string `json:"period_begins"`
PeriodBeginsHourLabel string `json:"period_begins_hour_label,omitempty"`
PeriodEnds string `json:"period_ends,omitempty"`
PeriodEndsHourLabel string `json:"period_ends_hour_label,omitempty"`
MaxPopPercent *int `json:"max_pop_percent,omitempty"`
MaxPopTime string `json:"max_pop_time,omitempty"`
MaxPopHourLabel string `json:"max_pop_hour_label,omitempty"`
PrecipitationType string `json:"precipitation_type,omitempty"`
ExpectationPhrase string `json:"expectation_phrase,omitempty"`
}
func buildPrecipTimingModule(ctx ModuleContext, _ any) (*module.Output, error) {
value := precipTimingValue(ctx.Derived.PrecipTiming, ctx.Timezone)
return &module.Output{ID: module.PrecipTiming, StanzaName: "precip_timing", Value: value}, nil
}
func precipTimingValue(timing forecast.PrecipTiming, timezone string) PrecipTimingModule {
value := PrecipTimingModule{
ProbabilityThreshold: timing.ProbabilityThreshold,
ThunderMentioned: timing.ThunderMentioned,
}
if timing.MaxPrecipitationProbability != nil {
value.MaxPopPercent = roundedInt(&timing.MaxPrecipitationProbability.Value)
value.MaxPopTime = clockLabel(timing.MaxPrecipitationProbability.Time, timezone)
}
for _, window := range timing.PrecipitationWindows {
item := PrecipitationWindowModule{
PeriodBegins: friendlyDateTimeLabel(window.Start, timezone),
PeriodBeginsHourLabel: hourMinuteLabel(window.Start, timezone),
}
if window.End != nil {
item.PeriodEnds = friendlyDateTimeLabel(*window.End, timezone)
item.PeriodEndsHourLabel = hourMinuteLabel(*window.End, timezone)
}
item.MaxPopPercent = roundedInt(&window.MaxPrecipitationProbability.Value)
item.MaxPopTime = clockLabel(window.MaxPrecipitationProbability.Time, timezone)
item.MaxPopHourLabel = hourMinuteLabel(window.MaxPrecipitationProbability.Time, timezone)
item.PrecipitationType = precipitationWindowType(window.TextDescriptions)
if item.MaxPopPercent != nil {
item.ExpectationPhrase = precipitationWindowExpectationPhrase(*item.MaxPopPercent, item.PrecipitationType)
}
value.PrecipitationWindows = append(value.PrecipitationWindows, item)
}
return value
}
func precipitationWindowType(descriptions []string) string {
combined := strings.ToLower(strings.Join(descriptions, " "))
switch {
case (strings.Contains(combined, "thunderstorm") || strings.Contains(combined, "t-storm")) &&
(strings.Contains(combined, "shower") || strings.Contains(combined, "rain")):
return "showers and thunderstorms"
case strings.Contains(combined, "freezing rain"):
return "freezing rain"
case strings.Contains(combined, "thunderstorm") || strings.Contains(combined, "t-storm"):
return "thunderstorms"
case strings.Contains(combined, "shower"):
return "showers"
case strings.Contains(combined, "snow"):
return "snow"
case strings.Contains(combined, "drizzle"):
return "drizzle"
case strings.Contains(combined, "rain"):
return "rain"
default:
return "precipitation"
}
}
func precipitationWindowExpectationPhrase(maxPopPercent int, precipitationType string) string {
if precipitationType == "" {
precipitationType = "precipitation"
}
switch {
case maxPopPercent >= precipTimingExpectLowerBound:
return fmt.Sprintf("Expect %s.", precipitationType)
case maxPopPercent >= precipTimingLikelyLowerBound:
return fmt.Sprintf("%s likely.", capitalizeFirst(strings.TrimSpace(precipitationType)))
case maxPopPercent >= precipTimingChanceLowerBound:
return fmt.Sprintf("Chance of %s.", precipitationType)
default:
return ""
}
}