-
Notifications
You must be signed in to change notification settings - Fork 237
/
get-weather.nu
313 lines (288 loc) · 13.4 KB
/
get-weather.nu
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
###################################################
## Weather Script based on IP Address v1.0
###################################################
def locations [] {
[
[location city_column state_column country_column lat_column lon_column];
["http://ip-api.com/json/" city region countryCode lat lon]
["https://ipapi.co/json/" city region_code country_code latitude longitude]
# ["https://freegeoip.app/json/" city region_code country_code latitude longitude] # doesn't appear to be free any longer
["https://ipwhois.app/json/" city region country_code latitude longitude]
]
}
def get_my_location [index: int] {
let loc_json = (http get (locations | select $index).0.location)
let city_column = (locations | select $index).0.city_column
let state_column = (locations | select $index).0.state_column
let country_column = (locations | select $index).0.country_column
let lat_column = (locations | select $index).0.lat_column
let lon_column = (locations | select $index).0.lon_column
# echo $loc_json
if ($city_column | str length) > 1 {
if ($state_column | str length) > 1 {
if ($country_column | str length) > 1 {
let lookup_state = ($loc_json | get ($state_column))
if ($lookup_state | str length) > 2 {
let state = (state_abbrev_lookup $lookup_state)
$"($loc_json | get ($city_column)),($state),($loc_json | get ($country_column))"
} else {
$"($loc_json | get ($city_column)),($loc_json | get ($state_column)),($loc_json | get ($country_column))"
}
} else {
$"($loc_json | get ($city_column)),($loc_json | get ($state_column))"
}
} else {
$"($loc_json | get ($city_column))"
}
} else {
"No City Found"
}
}
def get_location_by_ip [locIdx: int, token: string] {
let URL_QUERY_LOCATION = "https://api.openweathermap.org/geo/1.0/direct"
let location = (get_my_location $locIdx)
let url = $"($URL_QUERY_LOCATION)?q=($location)&limit=5&appid=($token)"
http get $url
}
def show-error [msg label err] {
let span = (metadata $err).span;
error make {msg: $msg, label: {text: $label, span: $span } }
}
def get_weather_by_ip [locIdx: int, units: string, token: string] {
# units
# f = imperial aka Fahrenheit
# c = metric aka Celsius
let URL_WEATHER = "https://api.openweathermap.org/data/2.5/weather"
let URL_FORECAST = "http://api.openweathermap.org/data/2.5/forecast/daily"
let coords = (get_location_by_ip $locIdx $token)
if ($coords | length) > 1 {
show-error "Error getting location" "There were more than one locations found" $coords
}
if $units == "f" {
let units = "imperial"
let url = $"($URL_WEATHER)?lat=($coords.lat.0)&lon=($coords.lon.0)&units=($units)&appid=($token)"
let url_forecast = $"($URL_FORECAST)?lat=($coords.lat.0)&lon=($coords.lon.0)&units=($units)&appid=($token)"
let weather = (http get $url)
let forecast_data = (http get $url_forecast)
let forecast = ($forecast_data.list | each {|day|
{
id: ($day.weather.0.id)
dt: ($day.dt * 1_000_000_000 | into string | into datetime -z local | format date '%a, %b %e') #'%Y-%m-%d')
high: ($day.temp.max)
low: ($day.temp.min)
}
})
let day1 = $"($forecast | get 0.dt) (get_emoji_by_id ($forecast | get 0.id | into string)) high: ($forecast | get 0.high | into string -d 1) low: ($forecast | get 0.low | into string -d 1)"
let day2 = $"($forecast | get 1.dt) (get_emoji_by_id ($forecast | get 1.id | into string)) high: ($forecast | get 1.high | into string -d 1) low: ($forecast | get 1.low | into string -d 1)"
let day3 = $"($forecast | get 2.dt) (get_emoji_by_id ($forecast | get 2.id | into string)) high: ($forecast | get 2.high | into string -d 1) low: ($forecast | get 2.low | into string -d 1)"
let day4 = $"($forecast | get 3.dt) (get_emoji_by_id ($forecast | get 3.id | into string)) high: ($forecast | get 3.high | into string -d 1) low: ($forecast | get 3.low | into string -d 1)"
let day5 = $"($forecast | get 4.dt) (get_emoji_by_id ($forecast | get 4.id | into string)) high: ($forecast | get 4.high | into string -d 1) low: ($forecast | get 4.low | into string -d 1)"
let day6 = $"($forecast | get 5.dt) (get_emoji_by_id ($forecast | get 5.id | into string)) high: ($forecast | get 5.high | into string -d 1) low: ($forecast | get 5.low | into string -d 1)"
let day7 = $"($forecast | get 6.dt) (get_emoji_by_id ($forecast | get 6.id | into string)) high: ($forecast | get 6.high | into string -d 1) low: ($forecast | get 6.low | into string -d 1)"
{
'Weather Location': $"($weather.name), ($weather.sys.country)"
Longitude: $weather.coord.lon
Latitude: $weather.coord.lat
Temperature: $"($weather.main.temp | into string -d 1) °F"
'Feels Like': $"($weather.main.feels_like | into string -d 1) °F"
Humidity: $weather.main.humidity
Pressure: $weather.main.pressure
Emoji: (get_icon_from_table $weather.weather.main.0)
'Forecast Day 1': $day1
'Forecast Day 2': $day2
'Forecast Day 3': $day3
'Forecast Day 4': $day4
'Forecast Day 5': $day5
'Forecast Day 6': $day6
'Forecast Day 7': $day7
}
} else {
let units = "metric"
let url = $"($URL_WEATHER)?lat=($coords.lat.0)&lon=($coords.lon.0)&units=($units)&appid=($token)"
let url_forecast = $"($URL_FORECAST)?lat=($coords.lat.0)&lon=($coords.lon.0)&units=($units)&appid=($token)"
let weather = (http get $url)
let forecast_data = (http get $url_forecast)
let forecast = ($forecast_data.list | each {|day|
{
id: ($day.weather.0.id)
dt: ($day.dt * 1_000_000_000 | into string | into datetime -z local | format date '%a, %b %e') #'%Y-%m-%d')
high: ($day.temp.max)
low: ($day.temp.min)
}
})
let day1 = $"($forecast | get 0.dt) (get_emoji_by_id ($forecast | get 0.id | into string)) high: ($forecast | get 0.high | into string -d 1) low: ($forecast | get 0.low | into string -d 1)"
let day2 = $"($forecast | get 1.dt) (get_emoji_by_id ($forecast | get 1.id | into string)) high: ($forecast | get 1.high | into string -d 1) low: ($forecast | get 1.low | into string -d 1)"
let day3 = $"($forecast | get 2.dt) (get_emoji_by_id ($forecast | get 2.id | into string)) high: ($forecast | get 2.high | into string -d 1) low: ($forecast | get 2.low | into string -d 1)"
let day4 = $"($forecast | get 3.dt) (get_emoji_by_id ($forecast | get 3.id | into string)) high: ($forecast | get 3.high | into string -d 1) low: ($forecast | get 3.low | into string -d 1)"
let day5 = $"($forecast | get 4.dt) (get_emoji_by_id ($forecast | get 4.id | into string)) high: ($forecast | get 4.high | into string -d 1) low: ($forecast | get 4.low | into string -d 1)"
let day6 = $"($forecast | get 5.dt) (get_emoji_by_id ($forecast | get 5.id | into string)) high: ($forecast | get 5.high | into string -d 1) low: ($forecast | get 5.low | into string -d 1)"
let day7 = $"($forecast | get 6.dt) (get_emoji_by_id ($forecast | get 6.id | into string)) high: ($forecast | get 6.high | into string -d 1) low: ($forecast | get 6.low | into string -d 1)"
{
'Weather Location': $"($weather.name), ($weather.sys.country)"
Longitude: $weather.coord.lon
Latitude: $weather.coord.lat
Temperature: $"($weather.main.temp | into string -d 1) °C"
'Feels Like': $"($weather.main.feels_like | into string -d 1) °C"
Humidity: $weather.main.humidity
Pressure: $weather.main.pressure
Emoji: (get_icon_from_table $weather.weather.main.0)
'Forecast Day 1': $day1
'Forecast Day 2': $day2
'Forecast Day 3': $day3
'Forecast Day 4': $day4
'Forecast Day 5': $day5
'Forecast Day 6': $day6
'Forecast Day 7': $day7
}
}
}
def weather_emoji_table [] {
{
Clear: (char sun)
Clouds: (char clouds)
Rain: (char rain)
Fog: (char fog)
Mist: (char mist)
Haze: (char haze)
Snow: (char snow)
Thunderstorm: (char thunderstorm)
}
}
def get_icon_from_table [w] {
weather_emoji_table | get $w
}
# Get the local weather by ip address
export def get_weather [
--locIdx(-l): int # The location id 0-2
--units(-u): string # The units "f" or "c"
] {
let token = "85a4e3c55b73909f42c6a23ec35b7147"
let is_loc_empty = ($locIdx == null)
let is_units_empty = ($units == null)
let no_loc_no_unit = ($is_loc_empty == true and $is_units_empty == true)
let no_loc_with_unit = ($is_loc_empty == true and $is_units_empty == false)
let with_loc_no_unit = ($is_loc_empty == false and $is_units_empty == true)
let with_loc_with_unit = ($is_loc_empty == false and $is_units_empty == false)
# This is a cautionary tale, the commented out code below is returning
# and autoview is viewing the data, so no structured data is being returned.
# The ramification to this is you can't do get_weather | select Temperature Emoji
# like you should be able to. The following uncommented section below fixes it.
# Hopefully we'll be able to fix this somehow because it's easy to fall into
# this hole without knowing.
# if $no_loc_no_unit {
# echo "no_loc_no_unit"
# (get_weather_by_ip 0 "f")
# } { }
# if $no_loc_with_unit {
# echo "no_loc_with_unit"
# (get_weather_by_ip 0 $units)
# } { }
# if $with_loc_no_unit {
# echo "with_loc_no_unit"
# (get_weather_by_ip $locIdx "f")
# } { }
# if $with_loc_with_unit {
# echo "with_loc_with_unit"
# (get_weather_by_ip $locIdx $units)
# } { }
if $no_loc_no_unit {
(get_weather_by_ip 0 "f" $token)
} else if $no_loc_with_unit {
(get_weather_by_ip 0 $units $token)
} else if $with_loc_no_unit {
(get_weather_by_ip $locIdx "f" $token)
} else if $with_loc_with_unit {
(get_weather_by_ip $locIdx $units $token)
}
}
def state_abbrev_lookup [state_name: string] {
# Weather Location 3 does not return state name abbreviations
# so we have to convert a state full name to a state abbreviation
let lookup_table = {
Alabama: AL
Alaska: AK
Arizona: AZ
Arkansas: AR
California: CA
Colorado: CO
Connecticut: CT
Delaware: DE
Florida: FL
Georgia: GA
Hawaii: HI
Idaho: ID
Illinois: IL
Indiana: IN
Iowa: IA
Kansas: KS
Kentucky: KY
Louisiana: LA
Maine: ME
Maryland: MD
Massachusetts: MA
Michigan: MI
Minnesota: MN
Mississippi: MS
Missouri: MO
Montana: MT
Nebraska: NE
Nevada: NV
'New Hampshire': NH
'New Jersey': NJ
'New Mexico': NM
'New York': NY
'North Carolina': NC
'North Dakota': ND
Ohio: OH
Oklahoma: OK
Oregon: OR
Pennsylvania: PA
'Rhode Island': RI
'South Carolina': SC
'South Dakota': SD
Tennessee: TN
Texas: TX
Utah: UT
Vermont: VT
Virginia: VA
Washington: WA
'West Virginia': WV
Wisconsin: WI
Wyoming: WY
}
$lookup_table | get $state_name
}
def get_emoji_by_id [id] {
let emoji_dict = ({
"200": "⚡", "201": "⚡", "202": "⚡", "210": "⚡", "211": "⚡", "212": "⚡", "221": "⚡", "230": "⚡",
"231": "⚡", "232": "⚡",
"300": "☔", "301": "☔", "302": "☔", "310": "☔", "311": "☔",
"312": "☔", "313": "☔", "314": "☔", "321": "☔",
"500": "☔", "501": "☔", "502": "☔", "503": "☔", "504": "☔",
"511": "☔", "520": "☔", "521": "☔", "522": "☔", "531": "☔",
"600": "❄️", "601": "❄️", "602": "❄️", "611": "❄️", "612": "❄️",
"613": "❄️", "615": "❄️", "616": "❄️", "620": "❄️", "621": "❄️",
"622": "❄️",
"701": "🌫️", "711": "🌫️", "721": "🌫️", "731": "🌫️", "741": "🌫️", "751": "🌫️", "761": "🌫️", "762": "🌫️",
"771": "🌫️",
"781": "🌀",
"800": "☀️",
"801": "🌤️", "802": "🌤️", "803": "☁️", "804": "☁️",
})
($emoji_dict | get $id)
}
# To run this call
# > get_weather
# it will default to location 0 and Fahrenheit degrees
# > get_weather -l 1
# This changes to location 1. Locations are listed in the locations custom command above
# > get_weather -l 2 -u c
# This uses location 2 and Celsius degrees. f = Fahrenheit, c = Celsius
# Since I live in the USA I have not tested outside the country.
# We'll take PRs for things that are broke or augmentations.
# HOW TO USE
# put this in your config.nu file
# use /path/to/get-weather.nu get_weather
#
# then from the nushell command prompt type
# get_weather