summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Teich <markus.teich@stusta.mhn.de>2017-03-21 03:38:02 +0100
committerMarkus Teich <markus.teich@stusta.mhn.de>2017-03-21 03:38:02 +0100
commit8fd3312b55623e52a21751391885aec82e5f666f (patch)
tree80fd33c75ac12e61d1d35eaff4302760ea8af726
parent32982d5e827c14ad3e81c5fbfdd7573b6265fd6c (diff)
fixup openweathermap.org backend
-rw-r--r--backends/openweather.go197
-rw-r--r--backends/openweathermap.org.go260
2 files changed, 260 insertions, 197 deletions
diff --git a/backends/openweather.go b/backends/openweather.go
deleted file mode 100644
index 264707c..0000000
--- a/backends/openweather.go
+++ /dev/null
@@ -1,197 +0,0 @@
-package backends
-
-import (
- "encoding/json"
- "flag"
- "fmt"
- "github.com/schachmat/wego/iface"
- "io/ioutil"
- "log"
- "net/http"
- "strings"
- "time"
-)
-
-type openWeatherConfig struct {
- apiKey string
- lang string
- debug bool
-}
-
-type openWeatherResponse struct {
- Cod string `json:"cod"`
- Message float64 `json:"message"`
- Cnt int `json:"cnt"`
- City cityResponseBlock `json:"city"`
- List []listBlock `json:"list"`
-}
-
-type listBlock struct {
- Dt int64 `json:"dt"`
- Dt_txt string `json:"dt_txt"`
- //Main section
- Main struct {
- Temp float32 `json:"temp"`
- Temp_min float32 `json:"temp_min"`
- Temp_max float32 `json:"temp_max"`
- Pressure float32 `json:"pressure"`
- Sea_level float32 `json:"sea_level"`
- Grnd_level float32 `json:"grnd_level"`
- Humidity int `json:"humidity"`
- Temp_kf float32 `json:"temp_kf"`
- } `json:"main"`
-
- Clouds struct {
- All int `json:"all"`
- } `json:"clouds"`
-
- Weather []struct {
- Description string `json:"description"`
- Icon string `json:"icon"`
- ID int `json:"id"`
- Main string `json:"main"`
- } `json:"weather"`
-
- Wind struct {
- Speed float32 `json:"speed"`
- Deg float32 `json:"deg"`
- } `json:"wind"`
-
- Rain struct {
- MM3h float32 `json:"3h"`
- } `json:"rain"`
-}
-
-type cityResponseBlock struct {
- Id int `json:"id"`
- Name string `json:"name"`
- Country string `json:"country"`
-}
-
-const (
- openweatherUri = "http://api.openweathermap.org/data/2.5/forecast?lat=%s&lon=%s&appid=%s&units=metric&lang=%s"
-)
-
-func (ow *openWeatherConfig) Setup() {
- flag.StringVar(&ow.apiKey, "openweather-api-key", "", "openweather backend: the api `KEY` to use")
- flag.StringVar(&ow.lang, "openweather-lang", "en", "openweather backend: the `LANGUAGE` to request to openweather")
- flag.BoolVar(&ow.debug, "openweather-debug", false, "openweather backend: print raw requests and responses")
-}
-
-func (ow *openWeatherConfig) fetch(url string) (*openWeatherResponse, error) {
- res, err := http.Get(url)
- if ow.debug {
- fmt.Printf("Fetching for %s \n", url)
- }
- if err != nil {
- return nil, fmt.Errorf(" Unable to get (%s) %v", url, err)
- }
- defer res.Body.Close()
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return nil, fmt.Errorf("Unable to read response body (%s): %v", url, err)
- }
-
- if ow.debug {
- fmt.Printf("Response (%s) %s", url, string(body))
- }
-
- var resp openWeatherResponse
- if err = json.Unmarshal(body, &resp); err != nil {
- return nil, fmt.Errorf("Unable to unmarshal response (%s): %v\nThe json body is: %s", url, err, string(body))
- }
- return &resp, nil
-}
-
-func (ow *openWeatherConfig) parseDaily(dataInfo []listBlock, numdays int) []iface.Day {
- var openWeather []iface.Day
- var day *iface.Day
-
- for _, data := range dataInfo {
- slot, err := ow.parseCond(data)
- if err != nil {
- log.Println("Error parsing hourly weather condition:", err)
- continue
- }
- if day == nil {
- day = new(iface.Day)
- day.Date = slot.Time
- }
- if day.Date.Day() == slot.Time.Day() {
- day.Slots = append(day.Slots, slot)
- }
- if day.Date.Day() != slot.Time.Day() {
- openWeather = append(openWeather, *day)
- if len(openWeather) >= numdays {
- break
- }
- day = new(iface.Day)
- day.Date = slot.Time
- day.Slots = append(day.Slots, slot)
- }
-
- }
- return openWeather
-}
-
-func (ow *openWeatherConfig) parseCond(dataInfo listBlock) (iface.Cond, error) {
- var ret iface.Cond
- codemap := map[int]iface.WeatherCode{
- 500: iface.CodeLightRain,
- 501: iface.CodeHeavyRain,
- 502: iface.CodeHeavyRain,
- 503: iface.CodeHeavyRain,
- 800: iface.CodeSunny,
- 802: iface.CodePartlyCloudy,
- 803: iface.CodePartlyCloudy,
- 804: iface.CodePartlyCloudy,
- }
- ret.Code = iface.CodeUnknown
- ret.Desc = dataInfo.Weather[0].Main
- ret.Humidity = &(dataInfo.Main.Humidity)
- ret.TempC = &(dataInfo.Main.Temp)
- if &dataInfo.Wind.Deg != nil {
- p := int(dataInfo.Wind.Deg)
- ret.WinddirDegree = &p
- }
- if &(dataInfo.Wind.Speed) != nil && (dataInfo.Wind.Speed) > 0 {
- windSpeed := (dataInfo.Wind.Speed * 3.6)
- ret.WindspeedKmph = &(windSpeed)
- }
- if val, ok := codemap[dataInfo.Weather[0].ID]; ok {
- ret.Code = val
- }
-
- if &dataInfo.Rain.MM3h != nil {
- mmh := (dataInfo.Rain.MM3h / 1000) / 3
- ret.PrecipM = &mmh
- }
-
- ret.Time = time.Unix(dataInfo.Dt, 0)
-
- return ret, nil
-}
-
-func (ow *openWeatherConfig) Fetch(location string, numdays int) iface.Data {
- var ret iface.Data
- s := strings.Split(location, ",")
-
- lat, lon := s[0], s[1]
-
- resp, err := ow.fetch(fmt.Sprintf(openweatherUri, lat, lon, ow.apiKey, ow.lang))
- if err != nil {
- log.Fatalf("Failed to fetch weather data: %v\n", err)
- }
- ret.Current, err = ow.parseCond(resp.List[0])
- ret.Location = fmt.Sprintf("%s", resp.City.Name)
-
- if err != nil {
- log.Fatalf("Failed to fetch weather data: %v\n", err)
- }
- ret.Forecast = ow.parseDaily(resp.List, numdays)
- return ret
-}
-
-func init() {
- iface.AllBackends["openweather"] = &openWeatherConfig{}
-}
diff --git a/backends/openweathermap.org.go b/backends/openweathermap.org.go
new file mode 100644
index 0000000..db06502
--- /dev/null
+++ b/backends/openweathermap.org.go
@@ -0,0 +1,260 @@
+package backends
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "github.com/schachmat/wego/iface"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "regexp"
+ "strings"
+ "time"
+)
+
+type openWeatherConfig struct {
+ apiKey string
+ lang string
+ debug bool
+}
+
+type openWeatherResponse struct {
+ Cod string `json:"cod"`
+ City struct {
+ Name string `json:"name"`
+ Country string `json:"country"`
+ } `json:"city"`
+ List []dataBlock `json:"list"`
+}
+
+type dataBlock struct {
+ Dt int64 `json:"dt"`
+ Main struct {
+ TempMin float32 `json:"temp_min"`
+ TempMax float32 `json:"temp_max"`
+ Humidity int `json:"humidity"`
+ } `json:"main"`
+
+ Weather []struct {
+ Description string `json:"description"`
+ ID int `json:"id"`
+ } `json:"weather"`
+
+ Wind struct {
+ Speed float32 `json:"speed"`
+ Deg float32 `json:"deg"`
+ } `json:"wind"`
+
+ Rain struct {
+ MM3h float32 `json:"3h"`
+ } `json:"rain"`
+}
+
+const (
+ openweatherURI = "http://api.openweathermap.org/data/2.5/forecast?%s&appid=%s&units=metric&lang=%s"
+)
+
+func (c *openWeatherConfig) Setup() {
+ flag.StringVar(&c.apiKey, "owm-api-key", "", "openweathermap backend: the api `KEY` to use")
+ flag.StringVar(&c.lang, "owm-lang", "en", "openweathermap backend: the `LANGUAGE` to request from openweathermap")
+ flag.BoolVar(&c.debug, "owm-debug", false, "openweathermap backend: print raw requests and responses")
+}
+
+func (c *openWeatherConfig) fetch(url string) (*openWeatherResponse, error) {
+ res, err := http.Get(url)
+ if c.debug {
+ fmt.Printf("Fetching %s\n", url)
+ }
+ if err != nil {
+ return nil, fmt.Errorf(" Unable to get (%s) %v", url, err)
+ }
+ defer res.Body.Close()
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return nil, fmt.Errorf("Unable to read response body (%s): %v", url, err)
+ }
+
+ if c.debug {
+ fmt.Printf("Response (%s):\n%s\n", url, string(body))
+ }
+
+ var resp openWeatherResponse
+ if err = json.Unmarshal(body, &resp); err != nil {
+ return nil, fmt.Errorf("Unable to unmarshal response (%s): %v\nThe json body is: %s", url, err, string(body))
+ }
+ if resp.Cod != "200" {
+ return nil, fmt.Errorf("Erroneous response body: %s", string(body))
+ }
+ return &resp, nil
+}
+
+func (c *openWeatherConfig) parseDaily(dataInfo []dataBlock, numdays int) []iface.Day {
+ var forecast []iface.Day
+ var day *iface.Day
+
+ for _, data := range dataInfo {
+ slot, err := c.parseCond(data)
+ if err != nil {
+ log.Println("Error parsing hourly weather condition:", err)
+ continue
+ }
+ if day == nil {
+ day = new(iface.Day)
+ day.Date = slot.Time
+ }
+ if day.Date.Day() == slot.Time.Day() {
+ day.Slots = append(day.Slots, slot)
+ }
+ if day.Date.Day() != slot.Time.Day() {
+ forecast = append(forecast, *day)
+ if len(forecast) >= numdays {
+ break
+ }
+ day = new(iface.Day)
+ day.Date = slot.Time
+ day.Slots = append(day.Slots, slot)
+ }
+
+ }
+ return forecast
+}
+
+func (c *openWeatherConfig) parseCond(dataInfo dataBlock) (iface.Cond, error) {
+ var ret iface.Cond
+ codemap := map[int]iface.WeatherCode{
+ 200: iface.CodeThunderyShowers,
+ 201: iface.CodeThunderyShowers,
+ 210: iface.CodeThunderyShowers,
+ 230: iface.CodeThunderyShowers,
+ 231: iface.CodeThunderyShowers,
+ 202: iface.CodeThunderyHeavyRain,
+ 211: iface.CodeThunderyHeavyRain,
+ 212: iface.CodeThunderyHeavyRain,
+ 221: iface.CodeThunderyHeavyRain,
+ 232: iface.CodeThunderyHeavyRain,
+ 300: iface.CodeLightRain,
+ 301: iface.CodeLightRain,
+ 310: iface.CodeLightRain,
+ 311: iface.CodeLightRain,
+ 313: iface.CodeLightRain,
+ 321: iface.CodeLightRain,
+ 302: iface.CodeHeavyRain,
+ 312: iface.CodeHeavyRain,
+ 314: iface.CodeHeavyRain,
+ 500: iface.CodeLightShowers,
+ 501: iface.CodeLightShowers,
+ 502: iface.CodeHeavyShowers,
+ 503: iface.CodeHeavyShowers,
+ 504: iface.CodeHeavyShowers,
+ 511: iface.CodeLightSleet,
+ 520: iface.CodeLightShowers,
+ 521: iface.CodeLightShowers,
+ 522: iface.CodeHeavyShowers,
+ 531: iface.CodeHeavyShowers,
+ 600: iface.CodeLightSnow,
+ 601: iface.CodeLightSnow,
+ 602: iface.CodeHeavySnow,
+ 611: iface.CodeLightSleet,
+ 612: iface.CodeLightSleetShowers,
+ 615: iface.CodeLightSleet,
+ 616: iface.CodeLightSleet,
+ 620: iface.CodeLightSnowShowers,
+ 621: iface.CodeLightSnowShowers,
+ 622: iface.CodeHeavySnowShowers,
+ 701: iface.CodeFog,
+ 711: iface.CodeFog,
+ 721: iface.CodeFog,
+ 741: iface.CodeFog,
+ 731: iface.CodeUnknown, // sand, dust whirls
+ 751: iface.CodeUnknown, // sand
+ 761: iface.CodeUnknown, // dust
+ 762: iface.CodeUnknown, // volcanic ash
+ 771: iface.CodeUnknown, // squalls
+ 781: iface.CodeUnknown, // tornado
+ 800: iface.CodeSunny,
+ 801: iface.CodePartlyCloudy,
+ 802: iface.CodeCloudy,
+ 803: iface.CodeVeryCloudy,
+ 804: iface.CodeVeryCloudy,
+ 900: iface.CodeUnknown, // tornado
+ 901: iface.CodeUnknown, // tropical storm
+ 902: iface.CodeUnknown, // hurricane
+ 903: iface.CodeUnknown, // cold
+ 904: iface.CodeUnknown, // hot
+ 905: iface.CodeUnknown, // windy
+ 906: iface.CodeUnknown, // hail
+ 951: iface.CodeUnknown, // calm
+ 952: iface.CodeUnknown, // light breeze
+ 953: iface.CodeUnknown, // gentle breeze
+ 954: iface.CodeUnknown, // moderate breeze
+ 955: iface.CodeUnknown, // fresh breeze
+ 956: iface.CodeUnknown, // strong breeze
+ 957: iface.CodeUnknown, // high wind, near gale
+ 958: iface.CodeUnknown, // gale
+ 959: iface.CodeUnknown, // severe gale
+ 960: iface.CodeUnknown, // storm
+ 961: iface.CodeUnknown, // violent storm
+ 962: iface.CodeUnknown, // hurricane
+ }
+
+ ret.Code = iface.CodeUnknown
+ ret.Desc = dataInfo.Weather[0].Description
+ ret.Humidity = &(dataInfo.Main.Humidity)
+ ret.TempC = &(dataInfo.Main.TempMin)
+ ret.FeelsLikeC = &(dataInfo.Main.TempMax)
+ if &dataInfo.Wind.Deg != nil {
+ p := int(dataInfo.Wind.Deg)
+ ret.WinddirDegree = &p
+ }
+ if &(dataInfo.Wind.Speed) != nil && (dataInfo.Wind.Speed) > 0 {
+ windSpeed := (dataInfo.Wind.Speed * 3.6)
+ ret.WindspeedKmph = &(windSpeed)
+ }
+ if val, ok := codemap[dataInfo.Weather[0].ID]; ok {
+ ret.Code = val
+ }
+
+ if &dataInfo.Rain.MM3h != nil {
+ mmh := (dataInfo.Rain.MM3h / 1000) / 3
+ ret.PrecipM = &mmh
+ }
+
+ ret.Time = time.Unix(dataInfo.Dt, 0)
+
+ return ret, nil
+}
+
+func (c *openWeatherConfig) Fetch(location string, numdays int) iface.Data {
+ var ret iface.Data
+ loc := ""
+
+ if len(c.apiKey) == 0 {
+ log.Fatal("No openweathermap.org API key specified.\nYou have to register for one at https://home.openweathermap.org/users/sign_up")
+ }
+ if matched, err := regexp.MatchString(`^-?[0-9]*(\.[0-9]+)?,-?[0-9]*(\.[0-9]+)?$`, location); matched && err == nil {
+ s := strings.Split(location, ",")
+ loc = fmt.Sprintf("lat=%s&lon=%s", s[0], s[1])
+ } else if matched, err = regexp.MatchString(`^[0-9].*`, location); matched && err == nil {
+ loc = "zip=" + location
+ } else {
+ loc = "q=" + location
+ }
+
+ resp, err := c.fetch(fmt.Sprintf(openweatherURI, loc, c.apiKey, c.lang))
+ if err != nil {
+ log.Fatalf("Failed to fetch weather data: %v\n", err)
+ }
+ ret.Current, err = c.parseCond(resp.List[0])
+ ret.Location = fmt.Sprintf("%s, %s", resp.City.Name, resp.City.Country)
+
+ if err != nil {
+ log.Fatalf("Failed to fetch weather data: %v\n", err)
+ }
+ ret.Forecast = c.parseDaily(resp.List, numdays)
+ return ret
+}
+
+func init() {
+ iface.AllBackends["openweathermap"] = &openWeatherConfig{}
+}