-
Notifications
You must be signed in to change notification settings - Fork 20
/
weather.go
158 lines (136 loc) · 3.45 KB
/
weather.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package main
import (
"fmt"
"time"
"github.com/jason0x43/go-alfred"
)
// Alert is a weather alert (e.g., severe thunderstorm)
type alert struct {
Description string `json:"description"`
Expires time.Time `json:"expires"`
URL string `json:"url"`
}
// DailyForecast represents future weather conditions
type dailyForecast struct {
Date time.Time
Summary string
Icon string
HighTemp temperature
LowTemp temperature
Sunrise time.Time
Sunset time.Time
Precip int
}
// HourlyForecast represents future weather conditions
type hourlyForecast struct {
Time time.Time
Summary string
Icon string
Temp temperature
ApparentTemp temperature
Precip int
}
// Int64 returns the value of the temperature in the currently configured units
// as an int64. Temperatures are assumed to be in Celsius by default
func (t temperature) Int64() int64 {
if config.Units == unitsMetric {
return round(float64(t))
}
return round(float64(t)*(9.0/5.0) + 32.0)
}
// temperature is a temperature in degrees Celsius
type temperature float64
// units identifies US or Metric units
type units string
// Weather is weather information
type Weather struct {
Current struct {
Summary string
Icon string
Humidity float64
Temp temperature
ApparentTemp temperature
Time time.Time
}
Daily []dailyForecast
Hourly []hourlyForecast
Alerts []alert
URL string
}
// IsAtNight indicates whether a given time is at night
func (w *Weather) IsAtNight(t time.Time) bool {
for i := 0; i < len(w.Daily)-1; i++ {
if t.After(w.Daily[i].Sunset) && t.Before(w.Daily[i+1].Sunrise) {
return true
}
}
return false
}
func getWeather(query string) (loc Location, weather Weather, err error) {
if err = validateConfig(); err != nil {
return
}
expired := time.Now().Sub(cache.Time).Minutes() >= 5.0 ||
time.Now().Format("1/2/2016") != cache.Time.Format("1/2/2016") ||
cache.Service != config.Service
if query == "" && !expired {
dlog.Printf("Using cached weather")
return config.Location, cache.Weather, nil
}
if query != "" {
var geos []Geocode
if geos, err = Locate(query); err != nil {
return
}
geo := geos[0]
loc = geo.Location()
dlog.Printf("got location")
} else {
loc = config.Location
dlog.Printf("using configured location")
}
if loc.Name != config.Location.Name || expired {
switch config.Service {
case serviceOpenWeather:
service := NewOpenWeather(config.OpenWeatherKey)
if weather, err = service.Forecast(loc); err != nil {
return
}
case serviceTomorrowIo:
service := NewTomorrowIo(config.TomorrowIoKey)
if weather, err = service.Forecast(loc); err != nil {
return
}
}
if loc.Name == config.Location.Name {
cache.Service = config.Service
cache.Time = time.Now()
cache.Weather = weather
if err := alfred.SaveJSON(cacheFile, &cache); err != nil {
dlog.Printf("Unable to save cache: %v", err)
}
}
} else {
weather = cache.Weather
}
return
}
func validateConfig() error {
if config.Service == "" {
return fmt.Errorf("Please choose a service")
}
hasKey := false
switch config.Service {
case serviceOpenWeather:
hasKey = config.OpenWeatherKey != ""
case serviceTomorrowIo:
hasKey = config.TomorrowIoKey != ""
}
if !hasKey {
return fmt.Errorf("Please add an API key for %s", config.Service)
}
if config.Location.Name == "" {
return fmt.Errorf("Please set a default location")
}
return nil
}