From ff4d399551d4efbfc0daae29cf5302cbeacd7f14 Mon Sep 17 00:00:00 2001 From: vikingowl Date: Sat, 19 Feb 2022 10:17:45 +0100 Subject: [PATCH] initial commit --- .gitignore | 37 +++++++ README.md | 1 + get-weather.go | 241 ++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 11 +++ go.sum | 8 ++ lib/interfaces.go | 115 ++++++++++++++++++++++ 6 files changed, 413 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 get-weather.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 lib/interfaces.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48a3fc2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Created by https://www.toptal.com/developers/gitignore/api/go +# Edit at https://www.toptal.com/developers/gitignore?templates=go + +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### Go Patch ### +/vendor/ +/Godeps/ + +# End of https://www.toptal.com/developers/gitignore/api/go +<<<<<<< HEAD + +======= +.env +get-weather +>>>>>>> 1f5ce74 (updated gitignore) diff --git a/README.md b/README.md new file mode 100644 index 0000000..a4121de --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +### Weather-Module-Script for Polybar diff --git a/get-weather.go b/get-weather.go new file mode 100644 index 0000000..5a2b2ba --- /dev/null +++ b/get-weather.go @@ -0,0 +1,241 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "strings" + + "github.com/joho/godotenv" + + "vikingowl/getweather/lib" +) + +// Settings +var city = "" +var apiKey = "" // get your api key on https://openweathermap.org/ +var location_lat = "" +var location_lon = "" +var units = "metric" +var temperature_unit = "C" + +var atmophere_icons_list = map[int]string{ + 701: "", // Mist + 711: "", // Smoke + 721: "", // Haze + 731: "", // Dust (Sand / dust whirls) + 741: "", // Fog + 751: "", // Sand + 761: "", // Dust + 762: "", // Ash + 771: "", // Squalls + 781: "", // Tornado +} + +// PrettyPrint to print struct in a readable way +func PrettyPrint(i interface{}) string { + s, _ := json.MarshalIndent(i, "", "\t") + return string(s) +} + +func setColor(apiIcon string) (string, string) { + var color string + var icon string + + colorIcons := map[string]map[string]string{ + "#fdd835": { // yellow + "01d": "", + "01n": "", + "02d": "", + "02n": "", + "04d": "", + "04n": "", + "11d": "", + "11n": "", + }, + "$foreground": { // foreground + "03d": "", + "03n": "", + }, + "#42a5f5": { // blue + "09d": "", + "09n": "", + "10d": "", + "10n": "", + }, + "#4dd0e1": { // cyan + "13d": "ﰕ", + "13n": "ﰕ", + }, + "#9e9e9e": { // gray + "50d": "", + "50n": "", + }, + } + + for colorI, icons := range colorIcons { + if iconI, f := icons[apiIcon]; f { + color = colorI + icon = iconI + } + } + + return color, icon +} + +func setUrls(apiKey string) lib.Urls { + urls := lib.Urls{} + baseUrl := "https://api.openweathermap.org/data/2.5" + if city == "" { + if location_lat == "" && location_lon == "" { + res, err := http.Get("https://location.services.mozilla.com/v1/geolocate?key=geoclue") + if err != nil { + log.Fatal(err) + } + + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + location := lib.GeoLocation{} + if err := json.Unmarshal(body, &location); err != nil { + log.Fatal(err) + } + + location_lat = fmt.Sprintf("%v", location.Location.Lat) + location_lon = fmt.Sprintf("%v", location.Location.Lon) + } + + urls.Url = fmt.Sprintf("%s/weather?lat=%s&lon=%s&units=%s&appid=%s", baseUrl, location_lat, location_lon, units, apiKey) + urls.Url_forecast = fmt.Sprintf("%s/forecast?lat=%s&lon=%s&units=%s&appid=%s", baseUrl, location_lat, location_lon, units, apiKey) + } else { + urls.Url = fmt.Sprintf("%s/weather?q=%s&units=%s&appid=%s", baseUrl, city, units, apiKey) + urls.Url_forecast = fmt.Sprintf("%s/forecast?q=%s&units=%s&appid=%s", baseUrl, city, units, apiKey) + } + + return urls +} + +func getWeather(url string) (lib.Weather, error) { + weather := lib.Weather{} + + res, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + if err := json.Unmarshal(body, &weather); err != nil { + log.Fatal("weather: ", err) + } + + return weather, err +} + +func getForecast(url string) (lib.Forecast, error) { + forecast := lib.Forecast{} + + res, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + if err := json.Unmarshal(body, &forecast); err != nil { + log.Fatal("forecast: ", err) + } + + return forecast, err +} + +func main() { + if err := godotenv.Load(".env"); err != nil { + log.Fatal(err) + } + if apiKey == "" { + apiKey = os.Getenv("API_KEY") + if apiKey == "" { + fmt.Println("You need an API KEY to use this script! Get one on https://openweathermap.org/") + os.Exit(1) + } + } + if location_lat == "" { + location_lat = os.Getenv("LAT") + } + if location_lon == "" { + location_lon = os.Getenv("LNG") + } + + urls := setUrls(apiKey) + weatherData, wErr := getWeather(urls.Url) + forecastData, fErr := getForecast(urls.Url_forecast) + + var curr string + var forecast string + var atmosphere string + var atmosphereForecast string + + // process weather data + if wErr == nil { + // Get info from data + id := int(weatherData.Weather[0].ID) + group := strings.Title(weatherData.Weather[0].Main) + apiIcon := weatherData.Weather[0].Icon + temp := fmt.Sprintf("%.1f", weatherData.Main.Temp) + + color, icon := setColor(apiIcon) + + // Load other icons for Atmosphere group + if group == "Atmosphere" { + atmosphere = "%{F#e57c46}" + atmophere_icons_list[id] + "%{F$foreground} " + temp + "°" + temperature_unit + "%{F-}" + } + + curr = "%{F" + color + "}" + icon + "%{F$foreground} " + temp + "°" + temperature_unit + "%{F-}" + } else { + forecast = "勒" + } + + // process forecast data + if fErr == nil { + // Get info from data + id := int(forecastData.List[0].Weather[0].ID) + group := strings.Title(forecastData.List[0].Weather[0].Main) + apiIcon := forecastData.List[0].Weather[0].Icon + temp := fmt.Sprintf("%.1f", forecastData.List[0].Main.Temp) + + color, icon := setColor(apiIcon) + + // Load other icons for Atmosphere group + if group == "Atmosphere" { + atmosphereForecast = "%{F#e57c46}" + atmophere_icons_list[id] + "{F$foreground} " + temp + "°" + temperature_unit + "%{F-}" + } + + forecast = "%{F" + color + "}" + icon + "%{F$foreground} " + temp + "°" + temperature_unit + "%{F-}" + } else { + forecast = "勒" + } + + if atmosphere == "" { + fmt.Printf("%s  %s", curr, forecast) + } else { + fmt.Printf("%s  %s", atmosphere, atmosphereForecast) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..91deafc --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module vikingowl/getweather + +go 1.17 + +require rsc.io/quote v1.5.2 + +require ( + github.com/joho/godotenv v1.4.0 // indirect + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect + rsc.io/sampler v1.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b6960c3 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y= +rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/lib/interfaces.go b/lib/interfaces.go new file mode 100644 index 0000000..17aa669 --- /dev/null +++ b/lib/interfaces.go @@ -0,0 +1,115 @@ +package lib + +type Urls struct { + Url string + Url_forecast string +} + +type GeoLocation struct { + Accuracy float64 `json:"accuracy"` + Location struct { + Lat float64 `json:"lat"` + Lon float64 `json:"lng"` + } `json:"location"` +} + +type Forecast struct { + Cod string `json:"cod"` + Message int `json:"message"` + Cnt int `json:"cnt"` + List []struct { + Dt int `json:"dt"` + Main struct { + Temp float64 `json:"temp"` + FeelsLike float64 `json:"feels_like"` + TempMin float64 `json:"temp_min"` + TempMax float64 `json:"temp_max"` + Pressure int `json:"pressure"` + SeaLevel int `json:"sea_level"` + GrndLevel int `json:"grnd_level"` + Humidity int `json:"humidity"` + TempKf float64 `json:"temp_kf"` + } `json:"main"` + Weather []struct { + ID int `json:"id"` + Main string `json:"main"` + Description string `json:"description"` + Icon string `json:"icon"` + } `json:"weather"` + Clouds struct { + All int `json:"all"` + } `json:"clouds"` + Wind struct { + Speed float64 `json:"speed"` + Deg int `json:"deg"` + Gust float64 `json:"gust"` + } `json:"wind"` + Visibility int `json:"visibility"` + Pop float64 `json:"pop"` + Rain struct { + ThreeH float64 `json:"3h"` + } `json:"rain,omitempty"` + Sys struct { + Pod string `json:"pod"` + } `json:"sys"` + DtTxt string `json:"dt_txt"` + Snow struct { + ThreeH float64 `json:"3h"` + } `json:"snow,omitempty"` + } `json:"list"` + City struct { + ID int `json:"id"` + Name string `json:"name"` + Coord struct { + Lat float64 `json:"lat"` + Lon float64 `json:"lon"` + } `json:"coord"` + Country string `json:"country"` + Population int `json:"population"` + Timezone int `json:"timezone"` + Sunrise int `json:"sunrise"` + Sunset int `json:"sunset"` + } `json:"city"` +} + +type Weather struct { + Coord struct { + Lon float64 `json:"lon"` + Lat float64 `json:"lat"` + } `json:"coord"` + Weather []struct { + ID int `json:"id"` + Main string `json:"main"` + Description string `json:"description"` + Icon string `json:"icon"` + } `json:"weather"` + Base string `json:"base"` + Main struct { + Temp float64 `json:"temp"` + FeelsLike float64 `json:"feels_like"` + TempMin float64 `json:"temp_min"` + TempMax float64 `json:"temp_max"` + Pressure int `json:"pressure"` + Humidity int `json:"humidity"` + } `json:"main"` + Visibility int `json:"visibility"` + Wind struct { + Speed float64 `json:"speed"` + Deg int `json:"deg"` + } `json:"wind"` + Clouds struct { + All int `json:"all"` + } `json:"clouds"` + Dt int `json:"dt"` + Sys struct { + Type int `json:"type"` + ID int `json:"id"` + Country string `json:"country"` + Sunrise int `json:"sunrise"` + Sunset int `json:"sunset"` + } `json:"sys"` + Timezone int `json:"timezone"` + ID int `json:"id"` + Name string `json:"name"` + Cod int `json:"cod"` +}