// openweathermap API package weather import ( "encoding/json" "fmt" "io/ioutil" "net/http" "net/url" "strconv" "time" ) const baseURL = `http://api.openweathermap.org/data/2.5/weather` type Current struct { Coord Coord Weather []Weather Base string // Internal Parameter Main Main Wind Wind Clouds Clouds Rain Rain Snow Snow Visibility int DT Timestamp // time of data calculation, unix, UTC Sys Sys ID int // City ID Name string // City Name Cod int // Internal Parameter } func (c Current) String() string { return fmt.Sprintf("%v: %v, %v, %v", c.Name, c.Weather[0], c.Main, c.Wind) } type Coord struct { Lon float64 // longitude Lat float64 // latitude } func (c Coord) String() string { return fmt.Sprint(c.Lon, c.Lat) } type Cond int type Weather struct { Cond Cond `json:"id"` // Station ID Main string // Group of weather parameters Description string // Weather condition within the group Icon string // Weather con id } func (w Weather) String() string { return fmt.Sprint(w.Cond) } type Main struct { Temp float64 // Temperature, Default Kelvin, Metric: Celsius Pressure int // Atmospheric pressure, hPa Humidity int // Humidity, % TempMin float64 `json:"temp_min"` // min temp TempMax float64 `json:"temp_max"` // max temp SeaLevel int `json:"sea_level"` // pressure on the sea level, hPa GrndLevel int `json:"grnd_level"` // pressure on the ground level, hPa } func (m Main) String() string { return fmt.Sprintf("%v°C, pressure: %v hPa, humidity: %v%%", m.Temp, m.Pressure, m.Humidity) } type Wind struct { Speed float64 // Wind speed. Default meter/sec Deg int // Wind direction, degrees (meteorogical) } func (w Wind) String() string { return fmt.Sprintf("wind: %v° %v m/s", w.Deg, w.Speed) } type Clouds struct { All int // Cloudness, % } func (c Clouds) String() string { return fmt.Sprintf("clouds: %v%%", c.All) } type Rain struct { Vol int `json:"3h"` // Rain volume for last 3 hours } func (r Rain) String() string { if r.Vol == 0 { return "" } return fmt.Sprintf("rain: %v mm/3h", r.Vol) } type Snow struct { Vol int `json:"3h"` // Snow volume for last 3 hours } func (s Snow) String() string { if s.Vol == 0 { return "" } return fmt.Sprintf("snow: %v mm/3h", s.Vol) } type Sys struct { Type int // Internal Parameter ID int // Internal Parameter Message float64 // Internal Parameter Country string // Country code Sunrise Timestamp // Sunrise time, unix, UTC Sunset Timestamp // Sunset time, unix, UTC } func (s Sys) String() string { return fmt.Sprintf("country: %v sunrise: %v sunset: %v", s.Country, s.Sunrise, s.Sunset) } type Timestamp struct{ time.Time } func (t *Timestamp) MarshalJSON() ([]byte, error) { ts := t.Unix() stamp := fmt.Sprint(ts) return []byte(stamp), nil } func (t *Timestamp) UnmarshalJSON(b []byte) error { ts, err := strconv.Atoi(string(b)) if err != nil { return err } *t = Timestamp{time.Unix(int64(ts), 0)} return nil } func get(param string) (Current, error) { var c Current resp, err := http.Get(baseURL + "?units=metric" + param) if err != nil { return c, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return c, err } err = json.Unmarshal(body, &c) return c, err } func ByCityName(name string) (Current, error) { return get(fmt.Sprintf("&q=%v", url.QueryEscape(name))) } func ByCityID(id int) (Current, error) { return get(fmt.Sprintf("&id=%v", id)) } func ByGeoCoord(lon, lat float64) (Current, error) { return get(fmt.Sprintf("&lon=%v&lat=%v", lon, lat)) } func ByZIPCode(zip int, country string) (Current, error) { return get(fmt.Sprintf("&zip=%v,%v", zip, country)) } func (c Cond) String() string { if cc, ok := condCodes[c]; ok { return cc } return "unknown" } var condCodes = map[Cond]string{ // Thunderstorm 200: `thunderstorm with light rain`, 201: `thunderstorm with rain`, 202: `thunderstorm with heavy rain`, 210: `light thunderstorm`, 211: `thunderstorm`, 212: `heavy thunderstorm`, 221: `ragged thunderstorm`, 230: `thunderstorm with light drizzle`, 231: `thunderstorm with drizzle`, 232: `thunderstorm with heavy drizzle`, // Drizzle 300: `light intensity drizzle`, 301: `drizzle`, 302: `heavy intensity drizzle`, 310: `light intensity drizzle rain`, 311: `drizzle rain`, 312: `heavy intensity drizzle rain`, 313: `shower rain and drizzle`, 314: `heavy shower rain and drizzle`, 321: `shower drizzle`, // Rain 500: `light rain`, 501: `moderate rain`, 502: `heavy intensity rain`, 503: `very heavy rain`, 504: `extreme rain`, 511: `freezing rain`, 520: `light intensity shower rain`, 521: `shower rain`, 522: `heavy intensity shower rain`, 531: `ragged shower rain`, // Snow 600: `light snow`, 601: `snow`, 602: `heavy snow`, 611: `sleet`, 612: `shower sleet`, 615: `light rain and snow`, 616: `rain and snow`, 620: `light shower snow`, 621: `shower snow`, 622: `heavy shower snow`, // Atmosphere 701: `mist`, 711: `smoke`, 721: `haze`, 731: `sand, dust whirls`, 741: `fog`, 751: `sand`, 761: `dust`, 762: `volcanic ash`, 771: `squalls`, 781: `tornado`, // Clouds 800: `clear sky`, 801: `few clouds`, 802: `scattered clouds`, 803: `broken clouds`, 804: `overcast clouds`, // Extreme 900: `tornado`, 901: `tropical storm`, 902: `hurricane`, 903: `cold`, 904: `hot`, 905: `windy`, 906: `hail`, // Additional 951: `calm`, 952: `light breeze`, 953: `gentle breeze`, 954: `moderate breeze`, 955: `fresh breeze`, 956: `strong breeze`, 957: `high wind, near gale`, 958: `gale`, 959: `severe gale`, 960: `storm`, 961: `violent storm`, 962: `hurricane`, }