89 lines
3.3 KiB
Go
89 lines
3.3 KiB
Go
package briefing
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/forecast"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
|
|
)
|
|
|
|
type DerivedDailySummaryModule struct {
|
|
Date string `json:"date,omitempty"`
|
|
HighTempF *int `json:"high_temp_f,omitempty"`
|
|
LowTempF *int `json:"low_temp_f,omitempty"`
|
|
MaxPopPercent *int `json:"max_pop_percent,omitempty"`
|
|
MaxPopWindow string `json:"max_pop_window,omitempty"`
|
|
FirstPrecipHour string `json:"first_precip_hour,omitempty"`
|
|
LastPrecipHour string `json:"last_precip_hour,omitempty"`
|
|
ThunderMentioned bool `json:"thunder_mentioned"`
|
|
MaxWindGustMph *int `json:"max_wind_gust_mph,omitempty"`
|
|
HeatIndexMaxF *int `json:"heat_index_max_f,omitempty"`
|
|
DominantConditions []string `json:"dominant_conditions,omitempty"`
|
|
Hazards []string `json:"hazards,omitempty"`
|
|
}
|
|
|
|
func buildDerivedDailySummaryModule(ctx ModuleContext, _ any) (*module.Output, error) {
|
|
summary := ctx.Derived.FirstDailySummary()
|
|
if summary == nil {
|
|
return nil, fmt.Errorf("daily summary facts are required")
|
|
}
|
|
value, err := derivedDailySummaryValue(*summary, ctx.Derived.PrecipTiming, ctx.Timezone)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &module.Output{ID: module.DerivedDailySummary, StanzaName: "derived_daily_summary", Value: value}, nil
|
|
}
|
|
|
|
func derivedDailySummaryValue(summary forecast.DailySummary, timing forecast.PrecipTiming, timezone string) (DerivedDailySummaryModule, error) {
|
|
value := DerivedDailySummaryModule{
|
|
Date: summary.Date,
|
|
ThunderMentioned: timing.ThunderMentioned,
|
|
}
|
|
conditions := map[string]struct{}{}
|
|
hazards := map[string]struct{}{}
|
|
var temperature forecast.Range
|
|
var apparent forecast.Range
|
|
var maxPop *forecast.TimedValue
|
|
var maxGust *forecast.TimedValue
|
|
var maxPopWindow timeutil.Period
|
|
for _, daypart := range summary.Dayparts {
|
|
addRange(&temperature, daypart.Temperature)
|
|
addRange(&apparent, daypart.ApparentTemperature)
|
|
if daypart.MaxPrecipitationProbability != nil {
|
|
if maxPop == nil || daypart.MaxPrecipitationProbability.Value > maxPop.Value {
|
|
copied := *daypart.MaxPrecipitationProbability
|
|
maxPop = &copied
|
|
maxPopWindow = daypart.Period
|
|
}
|
|
}
|
|
maxTimedValue(&maxGust, daypart.PeakWindGust)
|
|
if daypart.DominantCondition != "" {
|
|
conditions[daypart.DominantCondition] = struct{}{}
|
|
}
|
|
for _, hazard := range hazardsForIndicators(daypart.Indicators) {
|
|
hazards[hazard] = struct{}{}
|
|
}
|
|
}
|
|
for _, alert := range summary.AlertOverlaps {
|
|
if alert.Event != "" {
|
|
hazards[alert.Event] = struct{}{}
|
|
}
|
|
}
|
|
value.HighTempF = roundedInt(temperature.Max)
|
|
value.LowTempF = roundedInt(temperature.Min)
|
|
value.HeatIndexMaxF = roundedInt(apparent.Max)
|
|
if maxPop != nil {
|
|
value.MaxPopPercent = roundedInt(&maxPop.Value)
|
|
value.MaxPopWindow = periodClockLabel(maxPopWindow, timezone)
|
|
}
|
|
if maxGust != nil {
|
|
value.MaxWindGustMph = roundedInt(&maxGust.Value)
|
|
}
|
|
value.FirstPrecipHour = timedClockLabel(timing.FirstPrecipitation, timezone)
|
|
value.LastPrecipHour = timedClockLabel(timing.LastPrecipitation, timezone)
|
|
value.DominantConditions = sortedSet(conditions)
|
|
value.Hazards = sortedSet(hazards)
|
|
return value, nil
|
|
}
|