-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweather_query.go
175 lines (149 loc) · 5.25 KB
/
weather_query.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* Fetch the weather from YR using Norwegian place name.
For usage info, run the script without any arguments.
Written by Sigge Smelror (C) 2021, GNU GPL v. 3+
weather_query is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, version 3 or newer.
weather_query is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
URL: <https://www.gnu.org/licenses/gpl-3.0.txt>
Bugs/Issues: <https://github.com/sigg3/weather_query/issues>
*/
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
)
type GeoNorgeJson struct {
Data []struct {
Name string `json:"skrivemåte"`
Coordinates struct {
Long float64 `json:"øst"`
Lat float64 `json:"nord"`
} `json:"representasjonspunkt"`
} `json:"navn"`
}
type YrJson struct {
Data struct {
Timeseries []struct {
Time time.Time `json:"time"`
Data struct {
Instant struct {
Details struct {
AirPressureAtSeaLevel float64 `json:"air_pressure_at_sea_level"`
AirTemperature float64 `json:"air_temperature"`
CloudAreaFraction float64 `json:"cloud_area_fraction"`
RelativeHumidity float64 `json:"relative_humidity"`
WindFromDirection float64 `json:"wind_from_direction"`
WindSpeed float64 `json:"wind_speed"`
} `json:"details"`
} `json:"instant"`
} `json:"data,omitempty"`
} `json:"timeseries"`
} `json:"properties"`
}
// // getJson by Connor Peet @ https://stackoverflow.com/a/31129967
// func getJson(url string, target interface{}) error {
// fmt.Println(url)
// r, err := xClient.Get(url)
// if err != nil {
// return err
// }
// defer r.Body.Close()
// fmt.Println(json.NewDecoder(r.Body))
// return json.NewDecoder(r.Body).Decode(target)
// }
func main() {
// Get CLI arg (location) or print usage info
var uLoc string = "oslo"
if len(os.Args) > 1 {
uLoc = os.Args[1]
} else {
fmt.Println(strings.Join([]string{"Usage:", os.Args[0], "<place>"}, " "))
fmt.Println("Error: Location string argument missing. Use any place in Norway.")
os.Exit(1)
}
// Set HTTP request timeout (10 secs)
var xClient = &http.Client{Timeout: 10 * time.Second}
// create GET request for coordinates
const COORD_API string = "https://ws.geonorge.no/stedsnavn/v1/navn?sok="
const COORD_SUFFIX string = "&utkoordsys=4258&treffPerSide=1&side=1"
coordApiReq := strings.Join([]string{COORD_API, uLoc, COORD_SUFFIX}, "")
// Send GET request to COORD_API
coordApiResp, coordApiErr := xClient.Get(coordApiReq)
if coordApiErr != nil {
panic(coordApiErr)
}
// Convert to text uint8
coordTxt, readErr := ioutil.ReadAll(coordApiResp.Body)
if readErr != nil {
fmt.Println("Read error GeoNorge")
panic(readErr)
}
// Parse into geo using Location struct
geo := GeoNorgeJson{}
geoErr := json.Unmarshal(coordTxt, &geo)
if geoErr != nil {
fmt.Println("JSON error GeoNorge")
panic(geoErr)
}
// Pull relevant variables
var geoName string = geo.Data[0].Name
var geoLong float64 = geo.Data[0].Coordinates.Long
var geoLat float64 = geo.Data[0].Coordinates.Lat
// create GET request for weather query
const YR_API string = "https://api.met.no/weatherapi/locationforecast/2.0/compact.json?"
longLatStr := fmt.Sprintf("lat=%v&lon=%v", geoLat, geoLong) // lazy sprintf verb but oh well
weatherReq := strings.Join([]string{YR_API, longLatStr}, "")
// Construct GET request to weather_api
yrApiReq, yrReqErr := http.NewRequest("GET", weatherReq, nil)
if yrReqErr != nil {
panic(yrReqErr)
}
// Set User Agent header (YR requirement)
yrApiReq.Header.Set("Accept", "application/json")
yrApiReq.Header.Set("User-Agent", "GoLangTest/00.1")
// Send GET request to YR weather API
yrApiResp, yrApiErr := xClient.Do(yrApiReq)
if yrApiErr != nil {
panic(yrApiErr)
}
// Convert to text uint8
yrTxt, readYrErr := ioutil.ReadAll(yrApiResp.Body)
if readYrErr != nil {
fmt.Println("Read error YR")
panic(readYrErr)
}
// Parse into YR weather data struct
yrJson := YrJson{}
yrJsonErrErr := json.Unmarshal(yrTxt, &yrJson)
if yrJsonErrErr != nil {
panic(yrJsonErrErr)
}
// Pull relevant variables
yr := yrJson.Data.Timeseries[0].Data.Instant.Details
yrTime := yrJson.Data.Timeseries[0].Time
// Get temperatures
yrTempC := yr.AirTemperature
yrTempF := (yrTempC * (9 / 5)) + 32
// Print to screen (this is just lazy)
var output [8]string
output[0] = fmt.Sprintf("Current weather in: %s", geoName)
output[1] = fmt.Sprintf("Coordinates (long, lat): %v, %v", geoLong, geoLat)
output[2] = fmt.Sprintf("Observation timestamp: %v", yrTime)
output[3] = fmt.Sprintf("Temperature (celsius): %v\u00B0C", yrTempC)
output[4] = fmt.Sprintf("Temperature (fahrenheit): %v\u00B0F", yrTempF)
output[5] = fmt.Sprintf("Airpressure at sea level: %v hPa", yr.AirPressureAtSeaLevel)
output[6] = fmt.Sprintf("Current humidity: %v %%", yr.RelativeHumidity)
output[7] = fmt.Sprintf("Wind speed: %v m/sec", yr.WindSpeed)
for _, outLine := range output {
fmt.Println(outLine)
}
}