nushell-config/modules/get-weather.nu
2024-02-18 22:52:08 -06:00

316 lines
14 KiB
Plaintext

# From https://github.com/nushell/nu_scripts/blob/main/modules/weather/get-weather.nu
###################################################
## 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 Celcius
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 Celcius degrees. f = Fahrenheit, c = Celcius
# 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 commmand prompt type
# get_weather