-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathweather.go
159 lines (131 loc) · 4.72 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
159
package main
// @hipbot weather me today
// @hipbot weather me tomorrow
// Get all weather info for either today or tomorrow
// return an HTML list of weather attributes along with a pretty icon representation
// Many thanks to azuresol for the AWESOME & FREE ICONS! (http://azuresol.deviantart.com/)
import (
"encoding/json"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
)
const (
WEATHER_ICON_ENDPOINT = "https://cdn1.iconfinder.com/data/icons/sketchy-weather-icons-by-azuresol/64/"
WEATHER_FORECAST_ENDPOINT = "https://api.forecast.io/forecast/"
)
var weatherApiKey = os.Getenv("FORECAST_IO_API_KEY")
type WeatherResults struct {
Current Current `json:"currently"`
Day Day `json:"daily"`
}
type Current struct {
Temperature json.Number `json:"temperature"`
Icon string `json:"icon"`
}
type Day struct {
DailyData []*DailyData `json:"data"`
}
type DailyData struct {
Summary string `json:"summary"`
PrecipProbability json.Number `json:"precipProbability"`
TempMin json.Number `json:"temperatureMin"`
TempMax json.Number `json:"temperatureMax"`
}
// Get the weather forecast for <query> (today or tomorrow)
func weather(query string) string {
// Set query URL - uses latLngPair for location
queryUrl := WEATHER_FORECAST_ENDPOINT + weatherApiKey + "/" + latLngPair
// By default, the API will retrieve today's weather.
// To change that (give a date), we append a formatted date to the query URL
if query == "tomorrow" {
tomorrow := time.Now().AddDate(0, 0, 1)
queryUrl += "," + formattedTime(tomorrow)
}
// Send GET request, collect response
res, err := http.Get(queryUrl)
if err != nil {
log.Println(err)
return "error"
}
defer res.Body.Close()
// Decode JSON response
decoder := json.NewDecoder(res.Body)
results := new(WeatherResults)
decoder.Decode(results)
// Return a nicely formatted HTML version of results, complete with awesome icon
return formattedWeather(*results, query)
}
// Format the time.Time instance so that forecast.io API can read it
// return something like: "2013-09-15T16:37:00"
func formattedTime(t time.Time) string {
// t.String() will look something like c 21:59:55.459808262 -0700 PDT
// Split time string on spaces (splits between: date/time, time/zone_diff, zone_diff/zone)
timeParts := strings.Split(t.String(), " ")
// Get date in format 2009-11-10
stringDate := timeParts[0]
// Get time without part-seconds (21:59:55)
stringTime := strings.Split(timeParts[1], ".")[0]
// Final output will look like 2009-11-10T21:59:55
return (stringDate + "T" + stringTime)
}
// Format the weather forecast struct as pretty HTML for the Hipchat POST
func formattedWeather(weather WeatherResults, query string) string {
if len(weather.Day.DailyData) == 0 {
return "I found nothing! So sorry."
}
dailyData := weather.Day.DailyData[0]
formattedTitle := strings.Title(query) + "'s Weather"
// Slightly-indented title (ex: Today's Weather: partly cloudy.)
weatherHtml := " <strong>" + formattedTitle + "</strong>: " + dailyData.Summary + ".<br>"
// High & Low temperatures for <query> in Farenheit
weatherHtml += "<ul><li>High: " + string(dailyData.TempMax) + "°, Low: " + string(dailyData.TempMin) + "°</li>"
// Percent chance of precipitation (ex: Precipitation: 20% chance)
float64Chance, err := dailyData.PrecipProbability.Float64()
if err != nil {
log.Println("Error:", err)
return err.Error()
}
stringChance := strconv.FormatFloat(float64Chance*100, 'f', 2, 64)
weatherHtml += "<li>Precipitation: " + strings.Split(stringChance, ".")[0] + "% chance</li>"
// Show current weather if <query> == "today"
if query == "today" {
weatherHtml += "<li>Currently " + string(weather.Current.Temperature) + "°</li>"
}
// Map the response weather icon string to an actual icon
// icon string ex: "clear-night"
weatherHtml += "<li><img src='" + WEATHER_ICON_ENDPOINT + weatherIcon(weather.Current.Icon) + "'></li></ul>"
return weatherHtml
}
// Maps a weather type to its corresponding icon path
// Note that these icons are free for non-commercial use.
// Info on the author at http://azuresol.deviantart.com/
func weatherIcon(weatherType string) string {
switch weatherType {
case "clear-day":
return "32_cloud_weather.png"
case "clear-night":
return "31_cloud_weather.png"
case "rain":
return "11_cloud_weather.png"
case "snow":
return "41_cloud_weather.png"
case "sleet":
return "40_cloud_weather.png"
case "wind":
return "24_cloud_weather.png"
case "fog":
return "20_cloud_weather.png"
case "cloudy":
return "26_cloud_weather.png"
case "partly-cloudy-day":
return "30_cloud_weather.png"
case "partly-cloudy-night":
return "29_cloud_weather.png"
default:
return "na_cloud_weather.png"
}
}