diff --git a/.travis.yml b/.travis.yml
index 28614c4..729630c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
language: go
go:
- - 1.5.4
- - 1.6.2
+ - 1.15.8
+ - 1.16.2
env:
- GOARCH: amd64
- GOARCH: 386
diff --git a/Makefile b/Makefile
index 2398262..7305bbe 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,4 @@
-GOCMD = go
-GOBUILD = $(GOCMD) build
-GOGET = $(GOCMD) get -v
-GOCLEAN = $(GOCMD) clean
-GOINSTALL = $(GOCMD) install
-GOTEST = $(GOCMD) test
+GO = go
.PHONY: all
@@ -11,12 +6,5 @@ all: test
.PHONY: test
test:
- $(GOTEST) -v -covermode=count -coverprofile=coverage.out ./...
+ $(GO) test -v -covermode=count -coverprofile=coverage.out ./...
-.PHONY: build
-build: test
- $(GOBUILD)
-
-.PHONY: install
-install: test
- $(GOINSTALL)
diff --git a/README.md b/README.md
index cfe1db1..0662e6a 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[](https://godoc.org/github.com/briandowns/openweathermap) [](https://travis-ci.org/briandowns/openweathermap) [](https://coveralls.io/github/briandowns/openweathermap?branch=master)
-Go (golang) package for use with openweathermap.org's API.
+Go (golang) package for use with openweathermap.org's HTTP API.
For more detail about the library and its features, reference your local godoc once installed.
@@ -71,7 +71,25 @@ Gain access to OpenWeatherMap icons and condition codes.
## Supported Languages
-English - en, Russian - ru, Italian - it, Spanish - es (or sp), Ukrainian - uk (or ua), German - de, Portuguese - pt, Romanian - ro, Polish - pl, Finnish - fi, Dutch - nl, French - fr, Bulgarian - bg, Swedish - sv (or se), Chinese Traditional - zh_tw, Chinese Simplified - zh (or zh_cn), Turkish - tr, Croatian - hr, Catalan - ca
+- English - en
+- Russian - ru
+- Italian - it
+- Spanish - es (or sp)
+- Ukrainian - uk (or ua)
+- German - de
+- Portuguese - pt
+- Romanian - ro
+- Polish - pl
+- Finnish - fi
+- Dutch - nl
+- French - fr
+- Bulgarian - bg
+- Swedish - sv (or se)
+- Chinese Traditional - zh_tw
+- Chinese Simplified - zh (or zh_cn)
+- Turkish - tr
+- Croatian - hr
+- Catalan - ca
## Installation
@@ -81,7 +99,7 @@ go get github.com/briandowns/openweathermap
## Examples
-There are a few full examples in the examples directory that can be referenced. 1 is a command line application and 1 is a simple web application.
+Full, simple example.
```Go
package main
@@ -91,189 +109,100 @@ import (
"fmt"
"os"
- // Shortening the import reference name seems to make it a bit easier
- owm "github.com/briandowns/openweathermap"
+ "github.com/briandowns/openweathermap"
)
-var apiKey = os.Getenv("OWM_API_KEY")
-
func main() {
- w, err := owm.NewCurrent("F", "ru", apiKey) // fahrenheit (imperial) with Russian output
+ opts := openweathermap.Opts{
+ Lang: "EN",
+ Unit: "F",
+ Client: &http.Client{
+ Timeout: time.Second * 5,
+ },
+ }
+ owm, err := openweathermap.New(&opts)
if err != nil {
log.Fatalln(err)
}
- w.CurrentByName("Phoenix")
- fmt.Println(w)
-}
-
-```
-
-### Current Conditions by location name
-
-```Go
-func main() {
- w, err := owm.NewCurrent("K", "EN", apiKey) // (internal - OpenWeatherMap reference for kelvin) with English output
- if err != nil {
- log.Fatalln(err)
- }
-
- w.CurrentByName("Phoenix,AZ")
- fmt.Println(w)
+ cbn, err := owm.CurrentByName("Philadelphia")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ fmt.Printf("%#v\n", cbn)
}
```
### Forecast Conditions in imperial (fahrenheit) by coordinates
```Go
-func main() {
- w, err := owm.NewForecast("5", "F", "FI", apiKey) // valid options for first parameter are "5" and "16"
- if err != nil {
- log.Fatalln(err)
- }
-
- w.DailyByCoordinates(
- &owm.Coordinates{
- Longitude: -112.07,
- Latitude: 33.45,
- },
- 5 // five days forecast
- )
- fmt.Println(w)
+fdfbc, err := owm.FiveDayForecastByCoordinates(&openweathermap.Coordinates{Longitude: -75.1638, Latitude: 39.9523}, 10)
+if err != nil {
+ log.Fatalln(err)
}
+fmt.Printf("%#v\n", fdfbc)
```
### Current conditions in metric (celsius) by location ID
```Go
-func main() {
- w, err := owm.NewCurrent("C", "PL", apiKey)
- if err != nil {
- log.Fatalln(err)
- }
-
- w.CurrentByID(2172797)
- fmt.Println(w)
+owm.Unit = "C"
+cbi, err := owm.CurrentByID(4560349)
+if err != nil {
+ log.Fatalln(err)
}
+fmt.Printf("%#v\n", cbi)
```
### Current conditions by zip code. 2 character country code required
```Go
-func main() {
- w, err := owm.NewCurrent("F", "EN", apiKey)
- if err != nil {
- log.Fatalln(err)
- }
-
- w.CurrentByZip(19125, "US")
- fmt.Println(w)
+cbz, err := owm.CurrentByZip("19127", "")
+if err != nil {
+ log.Fatalln(err)
}
+fmt.Printf("%#v\n", cbz)
```
-### Configure http client
+### History by Name
```Go
-func main() {
- client := &http.Client{}
- w, err := owm.NewCurrent("F", "EN", apiKey, owm.WithHttpClient(client))
- if err != nil {
- log.Fatalln(err)
- }
+hbn, err := owm.HistoryByName("Philadelphia", &openweathermap.HistoricalParameters{
+ Start: 1369728000,
+ End: 1369789200,
+ Cnt: 4,
+})
+if err != nil {
+ log.Fatalln(err)
}
+fmt.Printf("%#v\n", hbn)
```
### Current UV conditions
```Go
-func main() {
- uv, err := owm.NewUV(apiKey)
- if err != nil {
- log.Fatalln(err)
- }
-
- coord := &owm.Coordinates{
- Longitude: 53.343497,
- Latitude: -6.288379,
- }
-
- if err := uv.Current(coord); err != nil {
- log.Fatalln(err)
- }
-
- fmt.Println(coord)
-}
-```
-
-### Historical UV conditions
-
-```Go
-func main() {
- uv, err := owm.NewUV(apiKey)
- if err != nil {
- log.Fatalln(err)
- }
-
- coord := &owm.Coordinates{
- Longitude: 54.995656,
- Latitude: -7.326834,
- }
-
- end := time.Now().UTC()
- start := time.Now().UTC().Add(-time.Hour * time.Duration(24))
-
- if err := uv.Historical(coord, start, end); err != nil {
- log.Fatalln(err)
- }
-}
-```
-
-### UV Information
-
-```Go
-func main() {
- uv, err := owm.NewUV(apiKey)
- if err != nil {
- log.Fatalln(err)
- }
-
- coord := &owm.Coordinates{
- Longitude: 53.343497,
- Latitude: -6.288379,
- }
-
- if err := uv.Current(coord); err != nil {
- log.Fatalln(err)
- }
-
- info, err := uv.UVInformation()
- if err != nil {
- log.Fatalln(err)
- }
-
- fmt.Println(info)
+uv, err := owm.UVCurrent(&openweathermap.Coordinates{
+ Latitude: 39.9523,
+ Longitude: -75.1638,
+})
+if err != nil {
+ log.Fatalln(err)
}
+fmt.Printf("%#v\n", uv)
```
### Pollution Information
```Go
-func main() {
- pollution, err := owm.NewPollution(apiKey)
- if err != nil {
- log.Fatalln(err)
- }
-
- params := &owm.PollutionParameters{
- Location: owm.Coordinates{
- Latitude: 0.0,
- Longitude: 10.0,
- },
- Datetime: "current",
- }
-
- if err := pollution.PollutionByParams(params); err != nil {
- log.Fatalln(err)
- }
+p, err := owm.PollutionByParams(&openweathermap.PollutionParameters{
+ Location: openweathermap.Coordinates{
+ Latitude: 39.9523,
+ Longitude: -75.1638,
+ },
+ Datetime: "2006-01-02T15:04:05-0700",
+})
+if err != nil {
+ log.Fatalln(err)
}
-```
+fmt.Printf("%#v\n", p)
+```
\ No newline at end of file
diff --git a/_examples/cli/weather.go b/_examples/cli/weather.go
deleted file mode 100644
index 72db125..0000000
--- a/_examples/cli/weather.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2015 Brian J. Downs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//
-// weather.go
-//
-// This application will go out and get the weather for the given
-// location and display it in the given data units (fahrenheit,
-// celcius, or kelvin). If the string "here" is provided as an
-// argument to the -l flag, the app will try to figure out where
-// it's being executed from based on geolocation from the IP address.
-//
-// Examples:
-// go run weather.go --help
-// go run weather.go -w Philadelphia -u f -l en # fahrenheit, English
-// go run weather.go -w here -u f -l ru # fahrenheit, Russian
-// go run weather.go -w Dublin -u c -l fi # celcius, Finnish
-// go run weather.go -w "Las Vegas" -u k -l es # kelvin, Spanish
-package main
-
-import (
- "encoding/json"
- "flag"
- owm "github.com/briandowns/openweathermap" // "owm" for easier use
- "io/ioutil"
- "log"
- "net/http"
- "os"
- "strings"
- "text/template"
-)
-
-// URL is a constant that contains where to find the IP locale info
-const URL = "http://ip-api.com/json"
-
-// template used for output
-const weatherTemplate = `Current weather for {{.Name}}:
- Conditions: {{range .Weather}} {{.Description}} {{end}}
- Now: {{.Main.Temp}} {{.Unit}}
- High: {{.Main.TempMax}} {{.Unit}}
- Low: {{.Main.TempMin}} {{.Unit}}
-`
-
-const forecastTemplate = `Weather Forecast for {{.City.Name}}:
-{{range .List}}Date & Time: {{.DtTxt}}
-Conditions: {{range .Weather}}{{.Main}} {{.Description}}{{end}}
-Temp: {{.Main.Temp}}
-High: {{.Main.TempMax}}
-Low: {{.Main.TempMin}}
-
-{{end}}
-`
-
-// Pointers to hold the contents of the flag args.
-var (
- whereFlag = flag.String("w", "", "Location to get weather. If location has a space, wrap the location in double quotes.")
- unitFlag = flag.String("u", "", "Unit of measure to display temps in")
- langFlag = flag.String("l", "", "Language to display temps in")
- whenFlag = flag.String("t", "current", "current | forecast")
-)
-
-// Data will hold the result of the query to get the IP
-// address of the caller.
-type Data struct {
- Status string `json:"status"`
- Country string `json:"country"`
- CountryCode string `json:"countryCode"`
- Region string `json:"region"`
- RegionName string `json:"regionName"`
- City string `json:"city"`
- Zip string `json:"zip"`
- Lat float64 `json:"lat"`
- Lon float64 `json:"lon"`
- Timezone string `json:"timezone"`
- ISP string `json:"isp"`
- ORG string `json:"org"`
- AS string `json:"as"`
- Message string `json:"message"`
- Query string `json:"query"`
-}
-
-// getLocation will get the location details for where this
-// application has been run from.
-func getLocation() (*Data, error) {
- response, err := http.Get(URL)
- if err != nil {
- return nil, err
- }
- defer response.Body.Close()
-
- result, err := ioutil.ReadAll(response.Body)
- if err != nil {
- return nil, err
- }
-
- r := &Data{}
- if err = json.Unmarshal(result, &r); err != nil {
- return nil, err
- }
- return r, nil
-}
-
-// getCurrent gets the current weather for the provided
-// location in the units provided.
-func getCurrent(location, units, lang string) (*owm.CurrentWeatherData, error) {
- w, err := owm.NewCurrent(units, lang, os.Getenv("OWM_API_KEY"))
- if err != nil {
- return nil, err
- }
- w.CurrentByName(location)
- return w, nil
-}
-func getForecast5(location, units, lang string) (*owm.Forecast5WeatherData, error) {
- w, err := owm.NewForecast("5", units, lang, os.Getenv("OWM_API_KEY"))
- if err != nil {
- return nil, err
- }
- w.DailyByName(location, 5)
- forecast := w.ForecastWeatherJson.(*owm.Forecast5WeatherData)
- return forecast, err
-}
-
-func main() {
- flag.Parse()
-
- // If there's any funkiness with cli args, tuck and roll...
- if len(*whereFlag) <= 1 || len(*unitFlag) != 1 || len(*langFlag) != 2 || len(*whenFlag) <= 1 {
- flag.Usage()
- os.Exit(1)
- }
-
- // Process request for location of "here"
- if strings.ToLower(*whereFlag) == "here" {
- loc, err := getLocation()
- if err != nil {
- log.Fatalln(err)
- }
- w, err := getCurrent(loc.City, *unitFlag, *langFlag)
- if err != nil {
- log.Fatalln(err)
- }
- tmpl, err := template.New("weather").Parse(weatherTemplate)
- if err != nil {
- log.Fatalln(err)
- }
-
- // Render the template and display
- err = tmpl.Execute(os.Stdout, w)
- if err != nil {
- log.Fatalln(err)
- }
- os.Exit(0)
- }
-
- if *whenFlag == "current" {
- // Process request for the given location
- w, err := getCurrent(*whereFlag, *unitFlag, *langFlag)
- if err != nil {
- log.Fatalln(err)
- }
- tmpl, err := template.New("weather").Parse(weatherTemplate)
- if err != nil {
- log.Fatalln(err)
- }
- // Render the template and display
- if err := tmpl.Execute(os.Stdout, w); err != nil {
- log.Fatalln(err)
- }
- } else { //forecast
- w, err := getForecast5(*whereFlag, *unitFlag, *langFlag)
- if err != nil {
- log.Fatalln(err)
- }
- tmpl, err := template.New("forecast").Parse(forecastTemplate)
- if err != nil {
- log.Fatalln(err)
- }
- // Render the template and display
- if err := tmpl.Execute(os.Stdout, w); err != nil {
- log.Fatalln(err)
- }
- }
-
- os.Exit(0)
-}
diff --git a/_examples/web/static/img/01d.png b/_examples/web/static/img/01d.png
deleted file mode 100644
index 7d2f792..0000000
Binary files a/_examples/web/static/img/01d.png and /dev/null differ
diff --git a/_examples/web/templates/here.html b/_examples/web/templates/here.html
deleted file mode 100644
index edb1fd6..0000000
--- a/_examples/web/templates/here.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- {{.Name}}
-
-
-
-
-
-
-
-
-
{{range .Weather}}
{{.Description}} {{end}}
-
-
-
- Now |
- High |
- Low |
-
-
- {{.Main.Temp}} {{.Unit}} | {{.Main.TempMax}} {{.Unit}} | {{.Main.TempMin}} {{.Unit}} |
-
-
-
-
-
diff --git a/_examples/web/weatherweb.go b/_examples/web/weatherweb.go
deleted file mode 100644
index 3519189..0000000
--- a/_examples/web/weatherweb.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Example of creating a web based application purely using
-// the net/http package to display weather information and
-// Twitter Bootstrap so it doesn't look like it's '92.
-//
-// To start the app, run:
-// go run weatherweb.go
-//
-// Accessible via: http://localhost:8888/here
-package main
-
-import (
- "encoding/json"
- "fmt"
- "html/template"
-
- owm "github.com/briandowns/openweathermap"
- // "io/ioutil"
-
- "net/http"
- "os"
-)
-
-// URL is a constant that contains where to find the IP locale info
-const URL = "http://ip-api.com/json"
-
-// Data will hold the result of the query to get the IP
-// address of the caller.
-type Data struct {
- Status string `json:"status"`
- Country string `json:"country"`
- CountryCode string `json:"countryCode"`
- Region string `json:"region"`
- RegionName string `json:"regionName"`
- City string `json:"city"`
- Zip string `json:"zip"`
- Lat float64 `json:"lat"`
- Lon float64 `json:"lon"`
- Timezone string `json:"timezone"`
- ISP string `json:"isp"`
- ORG string `json:"org"`
- AS string `json:"as"`
- Message string `json:"message"`
- Query string `json:"query"`
-}
-
-// getLocation will get the location details for where this
-// application has been run from.
-func getLocation() (*Data, error) {
- response, err := http.Get(URL)
- if err != nil {
- return nil, err
- }
- defer response.Body.Close()
- r := &Data{}
- if err = json.NewDecoder(response.Body).Decode(&r); err != nil {
- return nil, err
- }
- return r, nil
-}
-
-// getCurrent gets the current weather for the provided location in
-// the units provided.
-func getCurrent(l, u, lang string) (*owm.CurrentWeatherData, error) {
- w, err := owm.NewCurrent(u, lang, os.Getenv("OWM_API_KEY")) // Create the instance with the given unit
- if err != nil {
- return nil, err
- }
- w.CurrentByName(l) // Get the actual data for the given location
- return w, nil
-}
-
-// hereHandler will take are of requests coming in for the "/here" route.
-func hereHandler(w http.ResponseWriter, r *http.Request) {
- location, err := getLocation()
- if err != nil {
- fmt.Fprint(w, http.StatusInternalServerError)
- return
- }
- wd, err := getCurrent(location.City, "F", "en")
- if err != nil {
- fmt.Fprint(w, http.StatusInternalServerError)
- return
- }
- // Process our template
- t, err := template.ParseFiles("templates/here.html")
- if err != nil {
- fmt.Fprint(w, http.StatusInternalServerError)
- return
- }
- // We're doin' naughty things below... Ignoring icon file size and possible errors.
- _, _ = owm.RetrieveIcon("static/img", wd.Weather[0].Icon+".png")
-
- // Write out the template with the given data
- t.Execute(w, wd)
-}
-
-// Run the app
-func main() {
- http.HandleFunc("/here", hereHandler)
- // Make sure we can serve our icon files once retrieved
- http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
- http.ServeFile(w, r, r.URL.Path[1:])
- })
- http.ListenAndServe(":8888", nil)
-}
diff --git a/bulk_downloading.go b/bulk_downloading.go
new file mode 100644
index 0000000..49cc28b
--- /dev/null
+++ b/bulk_downloading.go
@@ -0,0 +1 @@
+package openweathermap
diff --git a/conditions.go b/conditions.go
index e73ecec..1e35a44 100644
--- a/conditions.go
+++ b/conditions.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -66,8 +66,8 @@ func RetrieveIcon(destination, iconFile string) (int64, error) {
return 0, nil
}
-// IconList is a slice of IconData pointers
-var IconList = []*IconData{
+// IconList is a slice of IconData.
+var IconList = []IconData{
{Condition: "clear sky", Day: "01d.png", Night: "01n.png"},
{Condition: "few clouds", Day: "02d.png", Night: "02n.png"},
{Condition: "scattered clouds", Day: "03d.png", Night: "03n.png"},
@@ -79,8 +79,8 @@ var IconList = []*IconData{
{Condition: "mist", Day: "50d.png", Night: "50n.png"},
}
-// ThunderstormConditions is a slice of ConditionData pointers
-var ThunderstormConditions = []*ConditionData{
+// ThunderstormConditions is a slice of ConditionData.
+var ThunderstormConditions = []ConditionData{
{ID: 200, Meaning: "thunderstorm with light rain", Icon1: "11d.png"},
{ID: 201, Meaning: "thunderstorm with rain", Icon1: "11d.png"},
{ID: 202, Meaning: "thunderstorm with heavy rain", Icon1: "11d.png"},
@@ -93,8 +93,8 @@ var ThunderstormConditions = []*ConditionData{
{ID: 232, Meaning: "thunderstorm with heavy drizzle", Icon1: "11d.png"},
}
-// DrizzleConditions is a slice of ConditionData pointers
-var DrizzleConditions = []*ConditionData{
+// DrizzleConditions is a slice of ConditionData.
+var DrizzleConditions = []ConditionData{
{ID: 300, Meaning: "light intensity drizzle", Icon1: "09d.png"},
{ID: 301, Meaning: "drizzle", Icon1: "09d.png"},
{ID: 302, Meaning: "heavy intensity drizzle", Icon1: "09d.png"},
@@ -106,8 +106,8 @@ var DrizzleConditions = []*ConditionData{
{ID: 321, Meaning: "shower drizzle", Icon1: "09d.png"},
}
-// RainConditions is a slice of ConditionData pointers
-var RainConditions = []*ConditionData{
+// RainConditions is a slice of ConditionData.
+var RainConditions = []ConditionData{
{ID: 500, Meaning: "light rain", Icon1: "09d.png"},
{ID: 501, Meaning: "moderate rain", Icon1: "09d.png"},
{ID: 502, Meaning: "heavy intensity rain", Icon1: "09d.png"},
@@ -120,8 +120,8 @@ var RainConditions = []*ConditionData{
{ID: 531, Meaning: "ragged shower rain", Icon1: "09d.png"},
}
-// SnowConditions is a slice of ConditionData pointers
-var SnowConditions = []*ConditionData{
+// SnowConditions is a slice of ConditionData.
+var SnowConditions = []ConditionData{
{ID: 600, Meaning: "light snow", Icon1: "13d.png"},
{ID: 601, Meaning: "snow", Icon1: "13d.png"},
{ID: 602, Meaning: "heavy snow", Icon1: "13d.png"},
@@ -134,8 +134,8 @@ var SnowConditions = []*ConditionData{
{ID: 622, Meaning: "heavy shower snow", Icon1: "13d.png"},
}
-// AtmosphereConditions is a slice of ConditionData pointers
-var AtmosphereConditions = []*ConditionData{
+// AtmosphereConditions is a slice of ConditionData.
+var AtmosphereConditions = []ConditionData{
{ID: 701, Meaning: "mist", Icon1: "50d.png"},
{ID: 711, Meaning: "smoke", Icon1: "50d.png"},
{ID: 721, Meaning: "haze", Icon1: "50d.png"},
@@ -148,8 +148,8 @@ var AtmosphereConditions = []*ConditionData{
{ID: 781, Meaning: "tornado", Icon1: "50d.png"},
}
-// CloudConditions is a slice of ConditionData pointers
-var CloudConditions = []*ConditionData{
+// CloudConditions is a slice of ConditionData.
+var CloudConditions = []ConditionData{
{ID: 800, Meaning: "clear sky", Icon1: "01d.png", Icon2: "01n.png"},
{ID: 801, Meaning: "few clouds", Icon1: "02d.png", Icon2: " 02n.png"},
{ID: 802, Meaning: "scattered clouds", Icon1: "03d.png", Icon2: "03d.png"},
@@ -157,8 +157,8 @@ var CloudConditions = []*ConditionData{
{ID: 804, Meaning: "overcast clouds", Icon1: "04d.png", Icon2: "04d.png"},
}
-// ExtremeConditions is a slice of ConditionData pointers
-var ExtremeConditions = []*ConditionData{
+// ExtremeConditions is a slice of ConditionData.
+var ExtremeConditions = []ConditionData{
{ID: 900, Meaning: "tornado", Icon1: ""},
{ID: 901, Meaning: "tropical storm", Icon1: ""},
{ID: 902, Meaning: "hurricane", Icon1: ""},
@@ -168,8 +168,8 @@ var ExtremeConditions = []*ConditionData{
{ID: 906, Meaning: "hail", Icon1: ""},
}
-// AdditionalConditions is a slive of ConditionData pointers
-var AdditionalConditions = []*ConditionData{
+// AdditionalConditions is a slicee of ConditionData.
+var AdditionalConditions = []ConditionData{
{ID: 951, Meaning: "calm", Icon1: ""},
{ID: 952, Meaning: "light breeze", Icon1: ""},
{ID: 953, Meaning: "gentle breeze", Icon1: ""},
diff --git a/conditions_test.go b/conditions_test.go
index e54e848..fa17710 100644
--- a/conditions_test.go
+++ b/conditions_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/current.go b/current.go
index 584903d..2fc8fb8 100644
--- a/current.go
+++ b/current.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,16 +15,15 @@
package openweathermap
import (
- "encoding/json"
+ "errors"
"fmt"
"net/url"
- "strings"
)
// CurrentWeatherData struct contains an aggregate view of the structs
// defined above for JSON to be unmarshaled into.
type CurrentWeatherData struct {
- GeoPos Coordinates `json:"coord"`
+ GeoPos Coordinates `json:"coord" xml:"coord"`
Sys Sys `json:"sys"`
Base string `json:"base"`
Weather []Weather `json:"weather"`
@@ -33,112 +32,71 @@ type CurrentWeatherData struct {
Clouds Clouds `json:"clouds"`
Rain Rain `json:"rain"`
Snow Snow `json:"snow"`
- Dt int `json:"dt"`
- ID int `json:"id"`
+ Dt int64 `json:"dt"`
+ ID int64 `json:"id"`
Name string `json:"name"`
Cod int `json:"cod"`
Timezone int `json:"timezone"`
- Unit string
- Lang string
- Key string
- *Settings
}
-// NewCurrent returns a new CurrentWeatherData pointer with the supplied parameters
-func NewCurrent(unit, lang, key string, options ...Option) (*CurrentWeatherData, error) {
- unitChoice := strings.ToUpper(unit)
- langChoice := strings.ToUpper(lang)
+// CurrentByName will provide the current weather with
+// the provided location name.
+func (o *OWM) CurrentByName(location string) (*CurrentWeatherData, error) {
+ base := fmt.Sprintf(baseURL, "appid=%s&q=%s&units=%s&lang=%s")
+ url := fmt.Sprintf(base, o.apiKey, url.QueryEscape(location), o.unit, o.lang)
- c := &CurrentWeatherData{
- Settings: NewSettings(),
- }
-
- if ValidDataUnit(unitChoice) {
- c.Unit = DataUnits[unitChoice]
- } else {
- return nil, errUnitUnavailable
- }
-
- if ValidLangCode(langChoice) {
- c.Lang = langChoice
- } else {
- return nil, errLangUnavailable
- }
- var err error
- c.Key, err = setKey(key)
- if err != nil {
+ var cwd CurrentWeatherData
+ if err := o.call(url, &cwd); err != nil {
return nil, err
}
- if err := setOptions(c.Settings, options); err != nil {
- return nil, err
- }
- return c, nil
+ return &cwd, nil
}
-// CurrentByName will provide the current weather with the provided
-// location name.
-func (w *CurrentWeatherData) CurrentByName(location string) error {
- response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(baseURL, "appid=%s&q=%s&units=%s&lang=%s"), w.Key, url.QueryEscape(location), w.Unit, w.Lang))
- if err != nil {
- return err
- }
- defer response.Body.Close()
+// CurrentByCoordinates will provide the current weather
+// with the provided location coordinates.
+func (o *OWM) CurrentByCoordinates(location *Coordinates) (*CurrentWeatherData, error) {
+ base := fmt.Sprintf(baseURL, "appid=%s&lat=%f&lon=%f&units=%s&lang=%s")
+ url := fmt.Sprintf(base, o.apiKey, location.Latitude, location.Longitude, o.unit, o.lang)
- if err := json.NewDecoder(response.Body).Decode(&w); err != nil {
- return err
- }
-
- return nil
-}
-
-// CurrentByCoordinates will provide the current weather with the
-// provided location coordinates.
-func (w *CurrentWeatherData) CurrentByCoordinates(location *Coordinates) error {
- response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(baseURL, "appid=%s&lat=%f&lon=%f&units=%s&lang=%s"), w.Key, location.Latitude, location.Longitude, w.Unit, w.Lang))
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- if err = json.NewDecoder(response.Body).Decode(&w); err != nil {
- return err
+ var cwd CurrentWeatherData
+ if err := o.call(url, &cwd); err != nil {
+ return nil, err
}
- return nil
+ return &cwd, nil
}
// CurrentByID will provide the current weather with the
// provided location ID.
-func (w *CurrentWeatherData) CurrentByID(id int) error {
- response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(baseURL, "appid=%s&id=%d&units=%s&lang=%s"), w.Key, id, w.Unit, w.Lang))
- if err != nil {
- return err
- }
- defer response.Body.Close()
+func (o *OWM) CurrentByID(id int) (*CurrentWeatherData, error) {
+ base := fmt.Sprintf(baseURL, "appid=%s&id=%d&units=%s&lang=%s")
+ url := fmt.Sprintf(base, o.apiKey, id, o.unit, o.lang)
- if err = json.NewDecoder(response.Body).Decode(&w); err != nil {
- return err
+ var cwd CurrentWeatherData
+ if err := o.call(url, &cwd); err != nil {
+ return nil, err
}
- return nil
+ return &cwd, nil
}
// CurrentByZip will provide the current weather for the
// provided zip code.
-func (w *CurrentWeatherData) CurrentByZip(zip int, countryCode string) error {
- response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(baseURL, "appid=%s&zip=%d,%s&units=%s&lang=%s"), w.Key, zip, countryCode, w.Unit, w.Lang))
- if err != nil {
- return err
- }
- defer response.Body.Close()
- if err = json.NewDecoder(response.Body).Decode(&w); err != nil {
- return err
+func (o *OWM) CurrentByZip(zip, countryCode string) (*CurrentWeatherData, error) {
+ base := fmt.Sprintf(baseURL, "appid=%s&zip=%s,%s&units=%s&lang=%s")
+ url := fmt.Sprintf(base, o.apiKey, zip, countryCode, o.unit, o.lang)
+
+ var cwd CurrentWeatherData
+ if err := o.call(url, &cwd); err != nil {
+ return nil, err
}
- return nil
+ return &cwd, nil
}
// CurrentByArea will provide the current weather for the
// provided area.
-func (w *CurrentWeatherData) CurrentByArea() {}
+func (o *OWM) CurrentByArea() (*CurrentWeatherData, error) {
+ return nil, errors.New("unimplemented")
+}
diff --git a/current_test.go b/current_test.go
index 8dc8d64..dc19e70 100644
--- a/current_test.go
+++ b/current_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,227 +16,276 @@ package openweathermap
import (
"net/http"
- "os"
"reflect"
"testing"
- "time"
)
-// currentWeather holds the query and response
-type currentWeather struct {
- query string
- weather CurrentWeatherData
-}
+// import (
+// "net/http"
+// "os"
+// "reflect"
+// "testing"
+// "time"
+// )
-// TestValidLanguageCode will verify that the language code passed in is indeed
-// a valid one for use with the API
-func TestValidLanguageCode(t *testing.T) {
- testCodes := []string{"EN", "DE", "blah"}
- for _, i := range testCodes {
- if !ValidLangCode(i) {
- t.Log("received expected bad code")
- }
- }
-}
+// // currentWeather holds the query and response
+// type currentWeather struct {
+// query string
+// weather CurrentWeatherData
+// }
-// TestNewCurrent will verify that a new instance of CurrentWeatherData is created
-func TestNewCurrent(t *testing.T) {
- t.Parallel()
+// // TestValidLanguageCode will verify that the language code passed in is indeed
+// // a valid one for use with the API
+// func TestValidLanguageCode(t *testing.T) {
+// testCodes := []string{"EN", "DE", "blah"}
+// for _, i := range testCodes {
+// if !ValidLangCode(i) {
+// t.Log("received expected bad code")
+// }
+// }
+// }
- for d := range DataUnits {
- t.Logf("Data unit: %s", d)
+// // TestNewCurrent will verify that a new instance of CurrentWeatherData is created
+// func TestNewCurrent(t *testing.T) {
+// t.Parallel()
- if ValidDataUnit(d) {
- c, err := NewCurrent(d, "en", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
+// for d := range DataUnits {
+// t.Logf("Data unit: %s", d)
- if _, err := NewCurrent(d, "blah", os.Getenv("OWM_API_KEY")); err != nil {
- t.Log("received expected bad language code error")
- }
+// if ValidDataUnit(d) {
+// c, err := NewCurrent(d, "en", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
- if reflect.TypeOf(c).String() != "*openweathermap.CurrentWeatherData" {
- t.Error("incorrect data type returned")
- }
- } else {
- t.Errorf("unusable data unit - %s", d)
- }
- }
-}
+// if _, err := NewCurrent(d, "blah", os.Getenv("OWM_API_KEY")); err != nil {
+// t.Log("received expected bad language code error")
+// }
-// TestNewCurrentWithCustomHttpClient will verify that a new instance of CurrentWeatherData
-// is created with custom http client
-func TestNewCurrentWithCustomHttpClient(t *testing.T) {
- hc := http.DefaultClient
- hc.Timeout = time.Duration(1) * time.Second
- c, err := NewCurrent("c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
- if err != nil {
- t.Error(err)
- }
+// if reflect.TypeOf(c).String() != "*openweathermap.CurrentWeatherData" {
+// t.Error("incorrect data type returned")
+// }
+// } else {
+// t.Errorf("unusable data unit - %s", d)
+// }
+// }
+// }
- if reflect.TypeOf(c).String() != "*openweathermap.CurrentWeatherData" {
- t.Error("incorrect data type returned")
- }
+// // TestNewCurrentWithCustomHttpClient will verify that a new instance of CurrentWeatherData
+// // is created with custom http client
+// func TestNewCurrentWithCustomHttpClient(t *testing.T) {
+// hc := http.DefaultClient
+// hc.Timeout = time.Duration(1) * time.Second
+// c, err := NewCurrent("c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
+// if err != nil {
+// t.Error(err)
+// }
- expected := time.Duration(1) * time.Second
- if c.client.Timeout != expected {
- t.Errorf("Expected Duration %v, but got %v", expected, c.client.Timeout)
- }
-}
+// if reflect.TypeOf(c).String() != "*openweathermap.CurrentWeatherData" {
+// t.Error("incorrect data type returned")
+// }
-// TestNewCurrentWithInvalidOptions will verify that returns an error with
-// invalid option
-func TestNewCurrentWithInvalidOptions(t *testing.T) {
- optionsPattern := [][]Option{
- {nil},
- {nil, nil},
- {WithHttpClient(&http.Client{}), nil},
- {nil, WithHttpClient(&http.Client{})},
- }
+// expected := time.Duration(1) * time.Second
+// if c.client.Timeout != expected {
+// t.Errorf("Expected Duration %v, but got %v", expected, c.client.Timeout)
+// }
+// }
- for _, options := range optionsPattern {
- c, err := NewCurrent("c", "en", os.Getenv("OWM_API_KEY"), options...)
- if err == errInvalidOption {
- t.Logf("Received expected invalid option error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidOption, err)
- }
- if c != nil {
- t.Errorf("Expected nil, but got %v", c)
- }
- }
-}
+// // TestNewCurrentWithInvalidOptions will verify that returns an error with
+// // invalid option
+// func TestNewCurrentWithInvalidOptions(t *testing.T) {
+// optionsPattern := [][]Option{
+// {nil},
+// {nil, nil},
+// {WithHttpClient(&http.Client{}), nil},
+// {nil, WithHttpClient(&http.Client{})},
+// }
-// TestNewCurrentWithInvalidHttpClient will verify that returns an error with
-// invalid http client
-func TestNewCurrentWithInvalidHttpClient(t *testing.T) {
+// for _, options := range optionsPattern {
+// c, err := NewCurrent("c", "en", os.Getenv("OWM_API_KEY"), options...)
+// if err == errInvalidOption {
+// t.Logf("Received expected invalid option error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidOption, err)
+// }
+// if c != nil {
+// t.Errorf("Expected nil, but got %v", c)
+// }
+// }
+// }
- c, err := NewCurrent("c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
- if err == errInvalidHttpClient {
- t.Logf("Received expected bad client error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
- }
- if c != nil {
- t.Errorf("Expected nil, but got %v", c)
- }
-}
+// // TestNewCurrentWithInvalidHttpClient will verify that returns an error with
+// // invalid http client
+// func TestNewCurrentWithInvalidHttpClient(t *testing.T) {
-// TestCurrentByName will verify that current data can be retrieved for a give
-// location by name
-func TestCurrentByName(t *testing.T) {
- t.Parallel()
-
- testCities := []currentWeather{
- {
- query: "Philadelphia",
- weather: CurrentWeatherData{
- ID: 4560349,
- Name: "Philadelphia",
- Main: Main{
- Temp: 35.6,
- },
- },
- },
- {
- query: "Newark",
- weather: CurrentWeatherData{
- ID: 5101798,
- Name: "Newark",
- Main: Main{
- Temp: 36.36,
- },
- },
- },
- {
- query: "Helena",
- weather: CurrentWeatherData{
- ID: 5656882,
- Name: "Helena",
- Main: Main{
- Temp: 42.8,
- },
- },
- },
- {
- query: "San Diego, CA",
- weather: CurrentWeatherData{
- ID: 5391811,
- Name: "San Diego",
- Main: Main{
- Temp: 56.53,
- },
- },
- },
- }
+// c, err := NewCurrent("c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
+// if err == errInvalidHttpClient {
+// t.Logf("Received expected bad client error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
+// }
+// if c != nil {
+// t.Errorf("Expected nil, but got %v", c)
+// }
+// }
- testBadCities := []string{"nowhere_", "somewhere_over_the_"}
+// // TestCurrentByName will verify that current data can be retrieved for a give
+// // location by name
+// func TestCurrentByName(t *testing.T) {
+// t.Parallel()
- c, err := NewCurrent("f", "ru", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
+// testCities := []currentWeather{
+// {
+// query: "Philadelphia",
+// weather: CurrentWeatherData{
+// ID: 4560349,
+// Name: "Philadelphia",
+// Main: Main{
+// Temp: 35.6,
+// },
+// },
+// },
+// {
+// query: "Newark",
+// weather: CurrentWeatherData{
+// ID: 5101798,
+// Name: "Newark",
+// Main: Main{
+// Temp: 36.36,
+// },
+// },
+// },
+// {
+// query: "Helena",
+// weather: CurrentWeatherData{
+// ID: 5656882,
+// Name: "Helena",
+// Main: Main{
+// Temp: 42.8,
+// },
+// },
+// },
+// {
+// query: "San Diego, CA",
+// weather: CurrentWeatherData{
+// ID: 5391811,
+// Name: "San Diego",
+// Main: Main{
+// Temp: 56.53,
+// },
+// },
+// },
+// }
- for _, city := range testCities {
- c.CurrentByName(city.query)
+// testBadCities := []string{"nowhere_", "somewhere_over_the_"}
- if os.Getenv("RTCP_HOST") != "" {
- if c.ID != city.weather.ID {
- t.Errorf("Excpect CityID %d, got %d", city.weather.ID, c.ID)
- }
- if c.Name != city.weather.Name {
- t.Errorf("Excpect City %s, got %s", city.weather.Name, c.Name)
- }
- if c.Main.Temp != city.weather.Main.Temp {
- t.Errorf("Excpect Temp %.2f, got %.2f", city.weather.Main.Temp, c.Main.Temp)
- }
- }
- }
+// c, err := NewCurrent("f", "ru", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
- for _, badCity := range testBadCities {
- if err := c.CurrentByName(badCity); err != nil {
- t.Log("received expected failure for bad city by name")
- }
- }
-}
+// for _, city := range testCities {
+// c.CurrentByName(city.query)
-// TestCurrentByCoordinates will verify that current data can be retrieved for a
-// given set of coordinates
-func TestCurrentByCoordinates(t *testing.T) {
- t.Parallel()
- c, err := NewCurrent("f", "DE", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error("Error creating instance of CurrentWeatherData")
- }
- c.CurrentByCoordinates(
- &Coordinates{
- Longitude: -112.07,
- Latitude: 33.45,
- },
- )
-}
+// if os.Getenv("RTCP_HOST") != "" {
+// if c.ID != city.weather.ID {
+// t.Errorf("Excpect CityID %d, got %d", city.weather.ID, c.ID)
+// }
+// if c.Name != city.weather.Name {
+// t.Errorf("Excpect City %s, got %s", city.weather.Name, c.Name)
+// }
+// if c.Main.Temp != city.weather.Main.Temp {
+// t.Errorf("Excpect Temp %.2f, got %.2f", city.weather.Main.Temp, c.Main.Temp)
+// }
+// }
+// }
-// TestCurrentByID will verify that current data can be retrieved for a given
-// location id
-func TestCurrentByID(t *testing.T) {
- t.Parallel()
- c, err := NewCurrent("c", "ZH", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error("Error creating instance of CurrentWeatherData")
- }
- c.CurrentByID(5344157)
-}
+// for _, badCity := range testBadCities {
+// if err := c.CurrentByName(badCity); err != nil {
+// t.Log("received expected failure for bad city by name")
+// }
+// }
+// }
-func TestCurrentByZip(t *testing.T) {
- w, err := NewCurrent("F", "EN", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
+// // TestCurrentByCoordinates will verify that current data can be retrieved for a
+// // given set of coordinates
+// func TestCurrentByCoordinates(t *testing.T) {
+// t.Parallel()
+// c, err := NewCurrent("f", "DE", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error("Error creating instance of CurrentWeatherData")
+// }
+// c.CurrentByCoordinates(
+// &Coordinates{
+// Longitude: -112.07,
+// Latitude: 33.45,
+// },
+// )
+// }
- if err := w.CurrentByZip(19125, "US"); err != nil {
- t.Error(err)
+// // TestCurrentByID will verify that current data can be retrieved for a given
+// // location id
+// func TestCurrentByID(t *testing.T) {
+// t.Parallel()
+// c, err := NewCurrent("c", "ZH", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error("Error creating instance of CurrentWeatherData")
+// }
+// c.CurrentByID(5344157)
+// }
+
+// func TestCurrentByZip(t *testing.T) {
+// w, err := NewCurrent("F", "EN", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if err := w.CurrentByZip(19125, "US"); err != nil {
+// t.Error(err)
+// }
+// }
+
+func TestOWM_CurrentByName(t *testing.T) {
+ type fields struct {
+ mode string
+ unit string
+ lang string
+ apiKey string
+ username string
+ password string
+ client *http.Client
+ }
+ type args struct {
+ location string
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want *CurrentWeatherData
+ wantErr bool
+ }{
+ //
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ o := &OWM{
+ mode: tt.fields.mode,
+ unit: tt.fields.unit,
+ lang: tt.fields.lang,
+ apiKey: tt.fields.apiKey,
+ username: tt.fields.username,
+ password: tt.fields.password,
+ client: tt.fields.client,
+ }
+ got, err := o.CurrentByName(tt.args.location)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("OWM.CurrentByName() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("OWM.CurrentByName() = %v, want %v", got, tt.want)
+ }
+ })
}
}
-
-func TestCurrentByArea(t *testing.T) {}
diff --git a/doc.go b/doc.go
index 39a41ff..a45ff80 100644
--- a/doc.go
+++ b/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/forecast.go b/forecast.go
index a5f240c..bf10ecd 100644
--- a/forecast.go
+++ b/forecast.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,18 +16,16 @@ package openweathermap
import (
"fmt"
- "io"
"net/url"
"strconv"
- "strings"
)
-// ForecastSys area population
+// ForecastSys area population.
type ForecastSys struct {
Population int `json:"population"`
}
-// Temperature holds returned termperate sure stats
+// Temperature holds returned termperate sure stats.
type Temperature struct {
Day float64 `json:"day"`
Min float64 `json:"min"`
@@ -37,126 +35,165 @@ type Temperature struct {
Morn float64 `json:"morn"`
}
-// City data for given location
+// City data for given location.
type City struct {
ID int `json:"id"`
Name string `json:"name"`
Coord Coordinates `json:"coord"`
Country string `json:"country"`
- Population int `json:"population"`
- Sys ForecastSys `json:"sys"`
+ Population int64 `json:"population"`
+ Timezone int64 `json:"timezome"`
+ Sunrise int64 `json:"sunrise"`
+ Sunset int64 `json:"sunset"`
}
-type ForecastWeather interface {
- DailyByName(location string, days int) error
- DailyByCoordinates(location *Coordinates, days int) error
- DailyByID(id, days int) error
+// Forecast5Weather holds specific query data.
+type ForecastFiveWeather struct {
+ Dt int64 `json:"dt"`
+ Main Main `json:"main"`
+ Weather []Weather `json:"weather"`
+ Clouds Clouds `json:"clouds"`
+ Wind Wind `json:"wind"`
+ Visibility int64 `json:"visibility"`
+ Pop float64 `json:"pop"`
+ Rain Rain `json:"rain"`
+ Sys Sys `json:"sys"`
+ Snow Snow `json:"snow"`
+ DtText string `json:"dt_text"`
}
-// json served by OWM API can take different forms, so all of them must be matched
-// by corresponding data type and unmarshall method
-type ForecastWeatherJson interface {
- Decode(r io.Reader) error
+// ForecastFiveWeatherData will hold returned data from queries.
+type ForecastFiveWeatherData struct {
+ COD string `json:"cod"`
+ Message int64 `json:"message"`
+ Cnt int64 `json:"cnt"`
+ List []ForecastFiveWeather `json:"list"`
+ City City `json:"city"`
}
-type ForecastWeatherData struct {
- Unit string
- Lang string
- Key string
- baseURL string
- *Settings
- ForecastWeatherJson
+// ForecastSixteenWeather holds specific query data.
+type ForecastSixteenWeather struct {
+ Dt int64 `json:"dt"`
+ Temp Temperature `json:"temp"`
+ Pressure float64 `json:"pressure"`
+ Humidity int64 `json:"humidity"`
+ Weather []Weather `json:"weather"`
+ Speed float64 `json:"speed"`
+ Deg int64 `json:"deg"`
+ Clouds int64 `json:"clouds"`
+ Snow float64 `json:"snow"`
+ Rain float64 `json:"rain"`
+ FeelsLike FeelsLikeFullDay `json:"feels_like"`
+ Pop float64 `json:"pop"`
}
-// NewForecast returns a new HistoricalWeatherData pointer with
-// the supplied arguments.
-func NewForecast(forecastType, unit, lang, key string, options ...Option) (*ForecastWeatherData, error) {
- unitChoice := strings.ToUpper(unit)
- langChoice := strings.ToUpper(lang)
+// ForecastSixteenWeatherData will hold returned data from queries.
+type ForecastSixteenWeatherData struct {
+ COD string `json:"cod"`
+ Message float64 `json:"message"`
+ City City `json:"city"`
+ Cnt int64 `json:"cnt"`
+ List []ForecastSixteenWeather `json:"list"`
+}
- if forecastType != "16" && forecastType != "5" {
- return nil, errForecastUnavailable
- }
+// FiveDayForecastByName will provide a five day forecast for the given location.
+func (o *OWM) FiveDayForecastByName(location string, cnt int) (*ForecastFiveWeatherData, error) {
+ url := fmt.Sprintf(forecastFiveBase, o.apiKey, "q="+url.QueryEscape(location), o.unit, o.lang, cnt)
- if !ValidDataUnit(unitChoice) {
- return nil, errUnitUnavailable
+ var fwd ForecastFiveWeatherData
+ if err := o.call(url, &fwd); err != nil {
+ return nil, err
}
+ fmt.Printf("%#v\n", fwd)
+ return &fwd, nil
+}
- if !ValidLangCode(langChoice) {
- return nil, errLangUnavailable
- }
+// FiveDayForecastByCoordinates will provide a five day forecast for the given coordinates.
+func (o *OWM) FiveDayForecastByCoordinates(location *Coordinates, cnt int) (*ForecastFiveWeatherData, error) {
+ pos := fmt.Sprintf("lat=%f&lon=%f", location.Latitude, location.Longitude)
+ url := fmt.Sprintf(forecastFiveBase, o.apiKey, pos, o.unit, o.lang, cnt)
- settings := NewSettings()
- if err := setOptions(settings, options); err != nil {
+ var fwd ForecastFiveWeatherData
+ if err := o.call(url, &fwd); err != nil {
return nil, err
}
- var err error
- k, err := setKey(key)
- if err != nil {
+ return &fwd, nil
+}
+
+// FiveDayForecastByID will provide a forecast for the given location ID.
+func (o *OWM) FiveDayForecastByID(id, cnt int) (*ForecastFiveWeatherData, error) {
+ idq := fmt.Sprintf("id=%s", strconv.Itoa(id))
+ url := fmt.Sprintf(forecastFiveBase, o.apiKey, idq, o.unit, o.lang, cnt)
+
+ var fwd ForecastFiveWeatherData
+ if err := o.call(url, &fwd); err != nil {
return nil, err
}
- forecastData := ForecastWeatherData{
- Unit: DataUnits[unitChoice],
- Lang: langChoice,
- Key: k,
- Settings: settings,
- }
- if forecastType == "16" {
- forecastData.baseURL = forecast16Base
- forecastData.ForecastWeatherJson = &Forecast16WeatherData{}
- } else {
- forecastData.baseURL = forecast5Base
- forecastData.ForecastWeatherJson = &Forecast5WeatherData{}
+ return &fwd, nil
+}
+
+// FiveDayForecastByZip will provide a forecast for the given zip code.
+func (o *OWM) FiveDayForecastByZip(zip, countryCode string, cnt int) (*ForecastFiveWeatherData, error) {
+ zipq := fmt.Sprintf("zip=%s,%s", zip, countryCode)
+ url := fmt.Sprintf(forecastFiveBase, o.apiKey, zipq, o.unit, o.lang, cnt)
+
+ var fwd ForecastFiveWeatherData
+ if err := o.call(url, &fwd); err != nil {
+ return nil, err
}
- return &forecastData, nil
+ return &fwd, nil
}
-// DailyByName will provide a forecast for the location given for the
-// number of days given.
-func (f *ForecastWeatherData) DailyByName(location string, days int) error {
- response, err := f.client.Get(fmt.Sprintf(f.baseURL, f.Key, fmt.Sprintf("%s=%s", "q", url.QueryEscape(location)), f.Unit, f.Lang, days))
- if err != nil {
- return err
- }
- defer response.Body.Close()
+// SixteenDayForecastByName will provide a sixteen day forecast for the given location.
+func (o *OWM) SixteenDayForecastByName(location string, cnt int) (*ForecastSixteenWeatherData, error) {
+ url := fmt.Sprintf(forecastSixteenBase, o.apiKey, "q="+url.QueryEscape(location), o.unit, o.lang, cnt)
- return f.ForecastWeatherJson.Decode(response.Body)
+ var fwd ForecastSixteenWeatherData
+ if err := o.call(url, &fwd); err != nil {
+ return nil, err
+ }
+ fmt.Printf("%#v\n", fwd)
+ return &fwd, nil
}
-// DailyByCoordinates will provide a forecast for the coordinates ID give
-// for the number of days given.
-func (f *ForecastWeatherData) DailyByCoordinates(location *Coordinates, days int) error {
- response, err := f.client.Get(fmt.Sprintf(f.baseURL, f.Key, fmt.Sprintf("lat=%f&lon=%f", location.Latitude, location.Longitude), f.Unit, f.Lang, days))
- if err != nil {
- return err
+// SixteenDayForecastByCoordinates will provide a sixteen day forecast for the given coordinates.
+func (o *OWM) SixteenDayForecastByCoordinates(location *Coordinates, cnt int) (*ForecastSixteenWeatherData, error) {
+ pos := fmt.Sprintf("lat=%f&lon=%f", location.Latitude, location.Longitude)
+ url := fmt.Sprintf(forecastSixteenBase, o.apiKey, pos, o.unit, o.lang, cnt)
+
+ var fwd ForecastSixteenWeatherData
+ if err := o.call(url, &fwd); err != nil {
+ return nil, err
}
- defer response.Body.Close()
- return f.ForecastWeatherJson.Decode(response.Body)
+ return &fwd, nil
}
-// DailyByID will provide a forecast for the location ID give for the
-// number of days given.
-func (f *ForecastWeatherData) DailyByID(id, days int) error {
- response, err := f.client.Get(fmt.Sprintf(f.baseURL, f.Key, fmt.Sprintf("%s=%s", "id", strconv.Itoa(id)), f.Unit, f.Lang, days))
- if err != nil {
- return err
+// SixteenDayForecastByID will provide a forecast for the given location ID.
+func (o *OWM) SixteenDayForecastByID(id, cnt int) (*ForecastSixteenWeatherData, error) {
+ idq := fmt.Sprintf("id=%s", strconv.Itoa(id))
+ url := fmt.Sprintf(forecastSixteenBase, o.apiKey, idq, o.unit, o.lang, cnt)
+
+ var fwd ForecastSixteenWeatherData
+ if err := o.call(url, &fwd); err != nil {
+ return nil, err
}
- defer response.Body.Close()
- return f.ForecastWeatherJson.Decode(response.Body)
+ return &fwd, nil
}
-// DailyByZip will provide a forecast for the provided zip code.
-func (f *ForecastWeatherData) DailyByZip(zip int, countryCode string, days int) error {
- response, err := f.client.Get(fmt.Sprintf(f.baseURL, f.Key, fmt.Sprintf("zip=%d,%s", zip, countryCode), f.Unit, f.Lang, days))
- if err != nil {
- return err
+// SixteenDayForecastByZip will provide a forecast for the given zip code.
+func (o *OWM) SixteenDayForecastByZip(zip, countryCode string, cnt int) (*ForecastSixteenWeatherData, error) {
+ zipq := fmt.Sprintf("zip=%s,%s", zip, countryCode)
+ url := fmt.Sprintf(forecastSixteenBase, o.apiKey, zipq, o.unit, o.lang, cnt)
+
+ var fwd ForecastSixteenWeatherData
+ if err := o.call(url, &fwd); err != nil {
+ return nil, err
}
- defer response.Body.Close()
- return f.ForecastWeatherJson.Decode(response.Body)
+ return &fwd, nil
}
diff --git a/forecast16.go b/forecast16.go
deleted file mode 100644
index 3ba9f51..0000000
--- a/forecast16.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package openweathermap
-
-import (
- "encoding/json"
- "io"
-)
-
-// Forecast16WeatherList holds specific query data
-type Forecast16WeatherList struct {
- Dt int `json:"dt"`
- Temp Temperature `json:"temp"`
- Pressure float64 `json:"pressure"`
- Humidity int `json:"humidity"`
- Weather []Weather `json:"weather"`
- Speed float64 `json:"speed"`
- Deg int `json:"deg"`
- Clouds int `json:"clouds"`
- Snow float64 `json:"snow"`
- Rain float64 `json:"rain"`
-}
-
-// Forecast16WeatherData will hold returned data from queries
-type Forecast16WeatherData struct {
- COD int `json:"cod"`
- Message string `json:"message"`
- City City `json:"city"`
- Cnt int `json:"cnt"`
- List []Forecast16WeatherList `json:"list"`
-}
-
-func (f *Forecast16WeatherData) Decode(r io.Reader) error {
- if err := json.NewDecoder(r).Decode(&f); err != nil {
- return err
- }
- return nil
-}
diff --git a/forecast5.go b/forecast5.go
deleted file mode 100644
index 9e52c20..0000000
--- a/forecast5.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package openweathermap
-
-import (
- "encoding/json"
- "io"
- "strings"
- "time"
-)
-
-type DtTxt struct {
- time.Time
-}
-
-func (dt *DtTxt) UnmarshalJSON(b []byte) error {
- t, err := time.Parse("2006-01-02 15:04:05", strings.Trim(string(b), "\""))
- dt.Time = t
- return err
-}
-
-func (t *DtTxt) MarshalJSON() ([]byte, error) {
- return json.Marshal(t)
-}
-
-// Forecast5WeatherList holds specific query data
-type Forecast5WeatherList struct {
- Dt int `json:"dt"`
- Main Main `json:"main"`
- Weather []Weather `json:"weather"`
- Clouds Clouds `json:"clouds"`
- Wind Wind `json:"wind"`
- Rain Rain `json:"rain"`
- Snow Snow `json:"snow"`
- DtTxt DtTxt `json:"dt_txt"`
-}
-
-// Forecast5WeatherData will hold returned data from queries
-type Forecast5WeatherData struct {
- // COD string `json:"cod"`
- // Message float64 `json:"message"`
- City City `json:"city"`
- Cnt int `json:"cnt"`
- List []Forecast5WeatherList `json:"list"`
-}
-
-func (f *Forecast5WeatherData) Decode(r io.Reader) error {
- if err := json.NewDecoder(r).Decode(&f); err != nil {
- return err
- }
- return nil
-}
diff --git a/forecast_test.go b/forecast_test.go
index bcd8dc0..3699839 100644
--- a/forecast_test.go
+++ b/forecast_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,167 +14,167 @@
package openweathermap
-import (
- "net/http"
- "os"
- "reflect"
- "testing"
- "time"
-)
-
-var forecastRange = []int{3, 7, 10}
-
-// TestNewForecast will make sure the a new instance of Forecast is returned
-func TestNewForecast(t *testing.T) {
- t.Parallel()
-
- for d := range DataUnits {
- t.Logf("Data unit: %s", d)
-
- if ValidDataUnit(d) {
- c5, err := NewForecast("5", d, "ru", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(c5).String() != "*openweathermap.ForecastWeatherData" {
- t.Error("incorrect data type returned")
- }
-
- c16, err := NewForecast("16", d, "ru", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(c16).String() != "*openweathermap.ForecastWeatherData" {
- t.Error("incorrect data type returned")
- }
- } else {
- t.Errorf("unusable data unit - %s", d)
- }
- }
-
- _, err := NewForecast("", "asdf", "en", os.Getenv("OWM_API_KEY"))
- if err == nil {
- t.Error("created instance when it shouldn't have")
- }
-}
-
-// TestNewForecastWithCustomHttpClient will verify that a new instance of ForecastWeatherData
-// is created with custom http client
-func TestNewForecastWithCustomHttpClient(t *testing.T) {
-
- hc := http.DefaultClient
- hc.Timeout = time.Duration(1) * time.Second
- f, err := NewForecast("5", "c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(f).String() != "*openweathermap.ForecastWeatherData" {
- t.Error("incorrect data type returned")
- }
-
- // expected := time.Duration(1) * time.Second
- // if f.client.Timeout != expected {
- // t.Errorf("Expected Duration %v, but got %v", expected, f.client.Timeout)
- // }
-}
-
-// TestNewForecastWithInvalidOptions will verify that returns an error with
-// invalid option
-func TestNewForecastWithInvalidOptions(t *testing.T) {
-
- optionsPattern := [][]Option{
- {nil},
- {nil, nil},
- {WithHttpClient(&http.Client{}), nil},
- {nil, WithHttpClient(&http.Client{})},
- }
-
- for _, options := range optionsPattern {
- c, err := NewForecast("5", "c", "en", os.Getenv("OWM_API_KEY"), options...)
- if err == errInvalidOption {
- t.Logf("Received expected invalid option error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidOption, err)
- }
- if c != nil {
- t.Errorf("Expected nil, but got %v", c)
- }
- }
-}
-
-// TestNewForecastWithCustomHttpClient will verify that returns an error with
-// invalid http client
-func TestNewForecastWithInvalidHttpClient(t *testing.T) {
-
- f, err := NewForecast("5", "c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
- if err == errInvalidHttpClient {
- t.Logf("Received expected bad client error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
- }
- if f != nil {
- t.Errorf("Expected nil, but got %v", f)
- }
-}
-
-// TestDailyByName will verify that a daily forecast can be retrieved for
-// a given named location
-func TestDailyByName(t *testing.T) {
- t.Parallel()
-
- f, err := NewForecast("5", "f", "fi", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- for _, d := range forecastRange {
- err = f.DailyByName("Dubai", d)
- if err != nil {
- t.Error(err)
- }
- }
-}
-
-// TestDailyByCooridinates will verify that a daily forecast can be retrieved
-// for a given set of coordinates
-func TestDailyByCoordinates(t *testing.T) {
- t.Parallel()
-
- f, err := NewForecast("5", "f", "PL", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- for _, d := range forecastRange {
- err = f.DailyByCoordinates(
- &Coordinates{
- Longitude: -112.07,
- Latitude: 33.45,
- }, d,
- )
- if err != nil {
- t.Error(err)
- }
- }
-}
-
-// TestDailyByID will verify that a daily forecast can be retrieved for a
-// given location ID
-func TestDailyByID(t *testing.T) {
- t.Parallel()
-
- f, err := NewForecast("5", "c", "fr", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- for _, d := range forecastRange {
- err = f.DailyByID(524901, d)
- if err != nil {
- t.Error(err)
- }
- }
-}
+// import (
+// "net/http"
+// "os"
+// "reflect"
+// "testing"
+// "time"
+// )
+
+// var forecastRange = []int{3, 7, 10}
+
+// // TestNewForecast will make sure the a new instance of Forecast is returned
+// func TestNewForecast(t *testing.T) {
+// t.Parallel()
+
+// for d := range DataUnits {
+// t.Logf("Data unit: %s", d)
+
+// if ValidDataUnit(d) {
+// c5, err := NewForecast("5", d, "ru", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(c5).String() != "*openweathermap.ForecastWeatherData" {
+// t.Error("incorrect data type returned")
+// }
+
+// c16, err := NewForecast("16", d, "ru", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(c16).String() != "*openweathermap.ForecastWeatherData" {
+// t.Error("incorrect data type returned")
+// }
+// } else {
+// t.Errorf("unusable data unit - %s", d)
+// }
+// }
+
+// _, err := NewForecast("", "asdf", "en", os.Getenv("OWM_API_KEY"))
+// if err == nil {
+// t.Error("created instance when it shouldn't have")
+// }
+// }
+
+// // TestNewForecastWithCustomHttpClient will verify that a new instance of ForecastWeatherData
+// // is created with custom http client
+// func TestNewForecastWithCustomHttpClient(t *testing.T) {
+
+// hc := http.DefaultClient
+// hc.Timeout = time.Duration(1) * time.Second
+// f, err := NewForecast("5", "c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(f).String() != "*openweathermap.ForecastWeatherData" {
+// t.Error("incorrect data type returned")
+// }
+
+// // expected := time.Duration(1) * time.Second
+// // if f.client.Timeout != expected {
+// // t.Errorf("Expected Duration %v, but got %v", expected, f.client.Timeout)
+// // }
+// }
+
+// // TestNewForecastWithInvalidOptions will verify that returns an error with
+// // invalid option
+// func TestNewForecastWithInvalidOptions(t *testing.T) {
+
+// optionsPattern := [][]Option{
+// {nil},
+// {nil, nil},
+// {WithHttpClient(&http.Client{}), nil},
+// {nil, WithHttpClient(&http.Client{})},
+// }
+
+// for _, options := range optionsPattern {
+// c, err := NewForecast("5", "c", "en", os.Getenv("OWM_API_KEY"), options...)
+// if err == errInvalidOption {
+// t.Logf("Received expected invalid option error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidOption, err)
+// }
+// if c != nil {
+// t.Errorf("Expected nil, but got %v", c)
+// }
+// }
+// }
+
+// // TestNewForecastWithCustomHttpClient will verify that returns an error with
+// // invalid http client
+// func TestNewForecastWithInvalidHttpClient(t *testing.T) {
+
+// f, err := NewForecast("5", "c", "en", os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
+// if err == errInvalidHttpClient {
+// t.Logf("Received expected bad client error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
+// }
+// if f != nil {
+// t.Errorf("Expected nil, but got %v", f)
+// }
+// }
+
+// // TestDailyByName will verify that a daily forecast can be retrieved for
+// // a given named location
+// func TestDailyByName(t *testing.T) {
+// t.Parallel()
+
+// f, err := NewForecast("5", "f", "fi", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// for _, d := range forecastRange {
+// err = f.DailyByName("Dubai", d)
+// if err != nil {
+// t.Error(err)
+// }
+// }
+// }
+
+// // TestDailyByCooridinates will verify that a daily forecast can be retrieved
+// // for a given set of coordinates
+// func TestDailyByCoordinates(t *testing.T) {
+// t.Parallel()
+
+// f, err := NewForecast("5", "f", "PL", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// for _, d := range forecastRange {
+// err = f.DailyByCoordinates(
+// &Coordinates{
+// Longitude: -112.07,
+// Latitude: 33.45,
+// }, d,
+// )
+// if err != nil {
+// t.Error(err)
+// }
+// }
+// }
+
+// // TestDailyByID will verify that a daily forecast can be retrieved for a
+// // given location ID
+// func TestDailyByID(t *testing.T) {
+// t.Parallel()
+
+// f, err := NewForecast("5", "c", "fr", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// for _, d := range forecastRange {
+// err = f.DailyByID(524901, d)
+// if err != nil {
+// t.Error(err)
+// }
+// }
+// }
diff --git a/global_weather_alerts.go b/global_weather_alerts.go
new file mode 100644
index 0000000..49cc28b
--- /dev/null
+++ b/global_weather_alerts.go
@@ -0,0 +1 @@
+package openweathermap
diff --git a/history.go b/history.go
index bcac611..7c70c8c 100644
--- a/history.go
+++ b/history.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,10 +15,8 @@
package openweathermap
import (
- "encoding/json"
"fmt"
"net/url"
- "strings"
)
// HistoricalParameters struct holds the (optional) fields to be
@@ -61,89 +59,43 @@ type HistoricalWeatherData struct {
CalcTime float64 `json:"calctime"`
Cnt int `json:"cnt"`
List []WeatherHistory `json:"list"`
- Unit string
- Key string
- *Settings
}
-// NewHistorical returns a new HistoricalWeatherData pointer with
-//the supplied arguments.
-func NewHistorical(unit, key string, options ...Option) (*HistoricalWeatherData, error) {
- h := &HistoricalWeatherData{
- Settings: NewSettings(),
- }
-
- unitChoice := strings.ToUpper(unit)
- if !ValidDataUnit(unitChoice) {
- return nil, errUnitUnavailable
- }
- h.Unit = DataUnits[unitChoice]
+// HistoryByName will return the history for the provided location.
+func (o *OWM) HistoryByName(location string, hp *HistoricalParameters) (*HistoricalWeatherData, error) {
+ base := fmt.Sprintf(historyURL, "appid=%s&%s&type=hour&mode=json&units=%s&lang=%s&cnt=%d&start=%d&end=%d")
+ url := fmt.Sprintf(base, o.apiKey, "q="+url.QueryEscape(location), o.unit, o.lang, hp.Cnt, hp.Start, hp.End)
- var err error
- h.Key, err = setKey(key)
- if err != nil {
+ var hwd HistoricalWeatherData
+ if err := o.call(url, &hwd); err != nil {
return nil, err
}
- if err := setOptions(h.Settings, options); err != nil {
- return nil, err
- }
- return h, nil
+ return &hwd, nil
}
-// HistoryByName will return the history for the provided location
-func (h *HistoricalWeatherData) HistoryByName(location string) error {
- response, err := h.client.Get(fmt.Sprintf(fmt.Sprintf(historyURL, "city?appid=%s&q=%s"), h.Key, url.QueryEscape(location)))
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- if err = json.NewDecoder(response.Body).Decode(&h); err != nil {
- return err
- }
+// HistoryByID will return the history for the provided id.
+func (o *OWM) HistoryByID(id int, hp *HistoricalParameters) (*HistoricalWeatherData, error) {
+ base := fmt.Sprintf(historyURL, "appid=%s&id=%d&type=hour&mode=json&units=%s&lang=%s&cnt=%d&start=%d&end=%d")
+ url := fmt.Sprintf(base, o.apiKey, id, o.unit, o.lang, hp.Cnt, hp.Start, hp.End)
- return nil
-}
-
-// HistoryByID will return the history for the provided location ID
-func (h *HistoricalWeatherData) HistoryByID(id int, hp ...*HistoricalParameters) error {
- if len(hp) > 0 {
- response, err := h.client.Get(fmt.Sprintf(fmt.Sprintf(historyURL, "city?appid=%s&id=%d&type=hour&start%d&end=%d&cnt=%d"), h.Key, id, hp[0].Start, hp[0].End, hp[0].Cnt))
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- if err = json.NewDecoder(response.Body).Decode(&h); err != nil {
- return err
- }
- }
-
- response, err := h.client.Get(fmt.Sprintf(fmt.Sprintf(historyURL, "city?appid=%s&id=%d"), h.Key, id))
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- if err = json.NewDecoder(response.Body).Decode(&h); err != nil {
- return err
+ var hwd HistoricalWeatherData
+ if err := o.call(url, &hwd); err != nil {
+ return nil, err
}
- return nil
+ return &hwd, nil
}
// HistoryByCoord will return the history for the provided coordinates
-func (h *HistoricalWeatherData) HistoryByCoord(location *Coordinates, hp *HistoricalParameters) error {
- response, err := h.client.Get(fmt.Sprintf(fmt.Sprintf(historyURL, "appid=%s&lat=%f&lon=%f&start=%d&end=%d"), h.Key, location.Latitude, location.Longitude, hp.Start, hp.End))
- if err != nil {
- return err
- }
- defer response.Body.Close()
+func (o *OWM) HistoryByCoord(location *Coordinates, hp *HistoricalParameters) (*HistoricalWeatherData, error) {
+ base := fmt.Sprintf(historyURL, "appid=%s&lat=%f&lon=%f&start=%d&end=%d")
+ url := fmt.Sprintf(base, o.apiKey, location.Latitude, location.Longitude, hp.Start, hp.End)
- if err = json.NewDecoder(response.Body).Decode(&h); err != nil {
- return err
+ var hwd HistoricalWeatherData
+ if err := o.call(url, &hwd); err != nil {
+ return nil, err
}
- return nil
+ return &hwd, nil
}
diff --git a/history_test.go b/history_test.go
index 6ac2a47..7e2835e 100644
--- a/history_test.go
+++ b/history_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,146 +14,146 @@
package openweathermap
-import (
- "net/http"
- "os"
- "reflect"
- "testing"
- "time"
-)
-
-// TestNewHistory verifies NewHistorical does as advertised
-func TestNewHistory(t *testing.T) {
- t.Parallel()
-
- for d := range DataUnits {
- t.Logf("Data unit: %s", d)
-
- if ValidDataUnit(d) {
- c, err := NewHistorical(d, os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
- if reflect.TypeOf(c).String() != "*openweathermap.HistoricalWeatherData" {
- t.Error("incorrect data type returned")
- }
- } else {
- t.Errorf("unusable data unit - %s", d)
- }
- }
-
- _, err := NewHistorical("asdf", os.Getenv("OWM_API_KEY"))
- if err == nil {
- t.Error("created instance when it shouldn't have")
- }
-}
-
-// TestNewHistoryWithCustomHttpClient will verify that a new instance of HistoricalWeatherData
-// is created with custom http client
-func TestNewHistoryWithCustomHttpClient(t *testing.T) {
-
- hc := http.DefaultClient
- hc.Timeout = time.Duration(1) * time.Second
- h, err := NewHistorical("c", os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(h).String() != "*openweathermap.HistoricalWeatherData" {
- t.Error("incorrect data type returned")
- }
-
- expected := time.Duration(1) * time.Second
- if h.client.Timeout != expected {
- t.Errorf("Expected Duration %v, but got %v", expected, h.client.Timeout)
- }
-}
-
-// TestNewHistoryWithInvalidOptions will verify that returns an error with
-// invalid option
-func TestNewHistoryWithInvalidOptions(t *testing.T) {
-
- optionsPattern := [][]Option{
- {nil},
- {nil, nil},
- {WithHttpClient(&http.Client{}), nil},
- {nil, WithHttpClient(&http.Client{})},
- }
-
- for _, options := range optionsPattern {
- c, err := NewHistorical("c", os.Getenv("OWM_API_KEY"), options...)
- if err == errInvalidOption {
- t.Logf("Received expected invalid option error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidOption, err)
- }
- if c != nil {
- t.Errorf("Expected nil, but got %v", c)
- }
- }
-}
-
-// TestNewHistoryWithInvalidHttpClient will verify that returns an error with
-// invalid http client
-func TestNewHistoryWithInvalidHttpClient(t *testing.T) {
-
- h, err := NewHistorical("c", os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
- if err == errInvalidHttpClient {
- t.Logf("Received expected bad client error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
- }
- if h != nil {
- t.Errorf("Expected nil, but got %v", h)
- }
-}
-
-// TestHistoryByName
-func TestHistoryByName(t *testing.T) {
- t.Parallel()
- h, err := NewHistorical("F", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
- if err := h.HistoryByName("Vancouver"); err != nil {
- t.Error(err)
- }
-}
-
-// TestHistoryByID
-func TestHistoryByID(t *testing.T) {
- t.Parallel()
- h, err := NewHistorical("F", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
- hp := &HistoricalParameters{
- Start: 1461598510,
- End: 1461588510,
- Cnt: 1,
- }
- if err := h.HistoryByID(5344157, hp); err != nil {
- t.Error(err)
- }
-}
-
-// TestHistoryByCoord
-func TestHistoryByCoord(t *testing.T) {
- t.Parallel()
- h, err := NewHistorical("F", os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
- coords := &Coordinates{
- Longitude: -112.07,
- Latitude: 33.45,
- }
- hp := &HistoricalParameters{
- Start: 1461598510,
- End: 1461588510,
- Cnt: 1,
- }
- if err := h.HistoryByCoord(coords, hp); err != nil {
- t.Error(err)
- }
-}
+// import (
+// "net/http"
+// "os"
+// "reflect"
+// "testing"
+// "time"
+// )
+
+// // TestNewHistory verifies NewHistorical does as advertised
+// func TestNewHistory(t *testing.T) {
+// t.Parallel()
+
+// for d := range DataUnits {
+// t.Logf("Data unit: %s", d)
+
+// if ValidDataUnit(d) {
+// c, err := NewHistorical(d, os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+// if reflect.TypeOf(c).String() != "*openweathermap.HistoricalWeatherData" {
+// t.Error("incorrect data type returned")
+// }
+// } else {
+// t.Errorf("unusable data unit - %s", d)
+// }
+// }
+
+// _, err := NewHistorical("asdf", os.Getenv("OWM_API_KEY"))
+// if err == nil {
+// t.Error("created instance when it shouldn't have")
+// }
+// }
+
+// // TestNewHistoryWithCustomHttpClient will verify that a new instance of HistoricalWeatherData
+// // is created with custom http client
+// func TestNewHistoryWithCustomHttpClient(t *testing.T) {
+
+// hc := http.DefaultClient
+// hc.Timeout = time.Duration(1) * time.Second
+// h, err := NewHistorical("c", os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(h).String() != "*openweathermap.HistoricalWeatherData" {
+// t.Error("incorrect data type returned")
+// }
+
+// expected := time.Duration(1) * time.Second
+// if h.client.Timeout != expected {
+// t.Errorf("Expected Duration %v, but got %v", expected, h.client.Timeout)
+// }
+// }
+
+// // TestNewHistoryWithInvalidOptions will verify that returns an error with
+// // invalid option
+// func TestNewHistoryWithInvalidOptions(t *testing.T) {
+
+// optionsPattern := [][]Option{
+// {nil},
+// {nil, nil},
+// {WithHttpClient(&http.Client{}), nil},
+// {nil, WithHttpClient(&http.Client{})},
+// }
+
+// for _, options := range optionsPattern {
+// c, err := NewHistorical("c", os.Getenv("OWM_API_KEY"), options...)
+// if err == errInvalidOption {
+// t.Logf("Received expected invalid option error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidOption, err)
+// }
+// if c != nil {
+// t.Errorf("Expected nil, but got %v", c)
+// }
+// }
+// }
+
+// // TestNewHistoryWithInvalidHttpClient will verify that returns an error with
+// // invalid http client
+// func TestNewHistoryWithInvalidHttpClient(t *testing.T) {
+
+// h, err := NewHistorical("c", os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
+// if err == errInvalidHttpClient {
+// t.Logf("Received expected bad client error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
+// }
+// if h != nil {
+// t.Errorf("Expected nil, but got %v", h)
+// }
+// }
+
+// // TestHistoryByName
+// func TestHistoryByName(t *testing.T) {
+// t.Parallel()
+// h, err := NewHistorical("F", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+// if err := h.HistoryByName("Vancouver"); err != nil {
+// t.Error(err)
+// }
+// }
+
+// // TestHistoryByID
+// func TestHistoryByID(t *testing.T) {
+// t.Parallel()
+// h, err := NewHistorical("F", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+// hp := &HistoricalParameters{
+// Start: 1461598510,
+// End: 1461588510,
+// Cnt: 1,
+// }
+// if err := h.HistoryByID(5344157, hp); err != nil {
+// t.Error(err)
+// }
+// }
+
+// // TestHistoryByCoord
+// func TestHistoryByCoord(t *testing.T) {
+// t.Parallel()
+// h, err := NewHistorical("F", os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+// coords := &Coordinates{
+// Longitude: -112.07,
+// Latitude: 33.45,
+// }
+// hp := &HistoricalParameters{
+// Start: 1461598510,
+// End: 1461588510,
+// Cnt: 1,
+// }
+// if err := h.HistoryByCoord(coords, hp); err != nil {
+// t.Error(err)
+// }
+// }
diff --git a/one_call.go b/one_call.go
new file mode 100644
index 0000000..af67124
--- /dev/null
+++ b/one_call.go
@@ -0,0 +1,136 @@
+package openweathermap
+
+import (
+ "fmt"
+)
+
+const (
+ oneCallBaseURL = "https://api.openweathermap.org/data/2.5/onecall?%s"
+)
+
+// OneTimeCurrent
+type OneTimeCurrent struct {
+ Dt int64 `json:"dt"`
+ Sunrise int64 `json:"sunrise"`
+ Sunset int64 `json:"sunset"`
+ Temp float64 `json:"temp"`
+ FeelsLike float64 `json:"feels_like"`
+ Pressure float64 `json:"pressure"`
+ Humidity int64 `json:"humidity"`
+ DewPoint float64 `json:"dew_point"`
+ UVI int64 `json:"uvi"`
+ Clouds int64 `json:"clouds"`
+ Visibility int64 `json:"visibility"`
+ WindSpeed float64 `json:"wind_speed"`
+ WindDeg float64 `json:"wind_deg"`
+ Weather []Weather `json:"weather"`
+}
+
+// OneTimeMinutely
+type OneTimeMinutely struct {
+ Dt int64 `json:"dt"`
+ Precipitation int64 `json:"precipitation"`
+}
+
+// OneTimeHourly
+type OneTimeHourly struct {
+ Dt int64 `json:"dt"`
+ Temp float64 `json:"temp"`
+ FeelsLike float64 `json:"feels_like"`
+ Pressure float64 `json:"pressure"`
+ Humidity int64 `json:"humidity"`
+ DewPoint float64 `json:"dew_point"`
+ UVI int64 `json:"uvi"`
+ Clouds int64 `json:"clouds"`
+ Visibility int64 `json:"visibility"`
+ WindSpeed float64 `json:"wind_speed"`
+ WindDeg float64 `json:"wind_deg"`
+ Weather []Weather `json:"weather"`
+ Pop float64 `json:"pop"`
+}
+
+// TempFullDay
+type TempFullDay struct {
+ Day float64 `json:"day"`
+ Min float64 `json:"Min"`
+ Max float64 `json:"max"`
+ Night float64 `json:"night"`
+ Eve float64 `json:"eve"`
+ Morn float64 `json:"morn"`
+}
+
+// FeelsLikeFullDay
+type FeelsLikeFullDay struct {
+ Day float64 `json:"day"`
+ Night float64 `json:"night"`
+ Eve float64 `json:"eve"`
+ Morn float64 `json:"morn"`
+}
+
+// OneTimeDaily
+type OneTimeDaily struct {
+ Dt int64 `json:"dt"`
+ Sunrise int64 `json:"sunrise"`
+ Sunset int64 `json:"sunset"`
+ Temp *TempFullDay `json:"tmep"`
+ FeelsLike *FeelsLikeFullDay `json:"feels_like"`
+ Pressure float64 `json:"pressure"`
+ Humidity int64 `json:"humidity"`
+ DewPoint float64 `json:"dew_point"`
+ WindSpeed float64 `json:"wind_speed"`
+ WindDeg float64 `json:"wind_deg"`
+ Weather []Weather `json:"weather"`
+ Clouds int64 `json:"clouds"`
+ Pop float64 `json:"pop"`
+ UVI int64 `json:"uvi"`
+}
+
+// Alert
+type Alert struct {
+ SenderName string `json:"sender_name"`
+ Event string `json:"event"`
+ Start int64 `json:"start"`
+ End int64 `json:"end"`
+ Description string `json:"description"`
+ EventLeve string `json:"event_level"`
+}
+
+// OneCallData
+type OneCallData struct {
+ Longitude float64 `json:"lon"`
+ Latitude float64 `json:"lat"`
+ Timezone string `json:"timezone"`
+ TimezoneOffset int64 `json:"timezone_offset"`
+ Current *OneTimeCurrent `json:"current"`
+ Weather *Weather `json:"weather"`
+ Minutely []OneTimeMinutely `json:"minutely"`
+ Hourly []OneTimeHourly `json:"hourly"`
+ Daily []OneTimeDaily `json:"daily"`
+ Alerts []Alert `json:"alerts"`
+}
+
+// OneCallCurrentAndForecast
+func (o *OWM) OneCallCurrentAndForecast(location *Coordinates) (*OneCallData, error) {
+ base := fmt.Sprintf(oneCallBaseURL, "lat=%s&lon=%s&exclude=%s&lang=%s&appid=%s")
+ url := fmt.Sprintf(base, location.Latitude, location.Longitude, o.unit, o.lang, o.apiKey)
+
+ var otc OneCallData
+ if err := o.call(url, &otc); err != nil {
+ return nil, err
+ }
+
+ return &otc, nil
+}
+
+// OneCallHistorical
+func (o *OWM) OneCallHistorical(location *Coordinates, dt int64) (*OneCallData, error) {
+ base := fmt.Sprintf(oneCallBaseURL, "lat=%s&lon=%s&exclude=%s&lang=%s&appid=%s")
+ url := fmt.Sprintf(base, location.Latitude, location.Longitude, o.unit, o.lang, o.apiKey)
+
+ var otc OneCallData
+ if err := o.call(url, &otc); err != nil {
+ return nil, err
+ }
+
+ return &otc, nil
+}
diff --git a/openweathermap.go b/openweathermap.go
index 7b9cb29..8b25e33 100644
--- a/openweathermap.go
+++ b/openweathermap.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,31 +15,36 @@
package openweathermap
import (
+ "encoding/json"
+ "encoding/xml"
"errors"
+ "fmt"
+ "io/ioutil"
"net/http"
+ "os"
+ "strings"
)
-var errUnitUnavailable = errors.New("unit unavailable")
-var errLangUnavailable = errors.New("language unavailable")
-var errInvalidKey = errors.New("invalid api key")
-var errInvalidOption = errors.New("invalid option")
-var errInvalidHttpClient = errors.New("invalid http client")
-var errForecastUnavailable = errors.New("forecast unavailable")
-
-// DataUnits represents the character chosen to represent the temperature notation
-var DataUnits = map[string]string{"C": "metric", "F": "imperial", "K": "internal"}
-var (
- baseURL = "http://api.openweathermap.org/data/2.5/weather?%s"
- iconURL = "http://openweathermap.org/img/w/%s"
- stationURL = "http://api.openweathermap.org/data/2.5/station?id=%d"
- forecast5Base = "http://api.openweathermap.org/data/2.5/forecast?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
- forecast16Base = "http://api.openweathermap.org/data/2.5/forecast/daily?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
- historyURL = "http://api.openweathermap.org/data/2.5/history/%s"
- pollutionURL = "http://api.openweathermap.org/pollution/v1/co/"
- uvURL = "http://api.openweathermap.org/data/2.5/"
- dataPostURL = "http://openweathermap.org/data/post"
+const (
+ baseURL = "https://api.openweathermap.org/data/2.5/weather?%s"
+ iconURL = "https://openweathermap.org/img/w/%s"
+ stationURL = "https://api.openweathermap.org/data/2.5/station?id=%d"
+ forecastFiveBase = "https://api.openweathermap.org/data/2.5/forecast?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
+ forecastSixteenBase = "https://api.openweathermap.org/data/2.5/forecast/daily?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
+ historyURL = "https://api.openweathermap.org/data/2.5/history/city?%s"
+ pollutionURL = "https://api.openweathermap.org/pollution/v1/co/"
+ uvURL = "https://api.openweathermap.org/data/2.5/"
+ dataPostURL = "https://openweathermap.org/data/post"
)
+// dataUnits represents the character chosen to represent
+// the temperature notation
+var dataUnits = map[string]string{
+ "C": "metric",
+ "F": "imperial",
+ "K": "internal",
+}
+
// LangCodes holds all supported languages to be used
// inspried and sourced from @bambocher (github.com/bambocher)
var LangCodes = map[string]string{
@@ -68,21 +73,121 @@ var LangCodes = map[string]string{
"ZH_CN": "Chinese Simplified",
}
-// Config will hold default settings to be passed into the
+// Opts will hold default settings to be passed into the
// "NewCurrent, NewForecast, etc}" functions.
-type Config struct {
- Mode string // user choice of JSON or XML
- Unit string // measurement for results to be displayed. F, C, or K
- Lang string // should reference a key in the LangCodes map
- APIKey string // API Key for connecting to the OWM
- Username string // Username for posting data
- Password string // Pasword for posting data
+type Opts struct {
+ Host string //
+ Mode string // user choice of JSON or XML
+ Unit string // measurement for results to be displayed. F, C, or K
+ Lang string // should reference a key in the LangCodes map
+ APIKey string // API Key for connecting to the OWM
+ Username string // Username for posting data
+ Password string // Pasword for posting data
+ Client *http.Client // HTTP client to use for calls to OWM
+}
+
+// OWM
+type OWM struct {
+ host string //
+ mode string // user choice of JSON or XML
+ unit string // measurement for results to be displayed. F, C, or K
+ lang string // should reference a key in the LangCodes map
+ apiKey string // API Key for connecting to the OWM
+ username string // Username for posting data
+ password string // Pasword for posting data
+ client *http.Client // HTTP client to use for calls to OWM
+}
+
+// New
+func New(opts *Opts) (*OWM, error) {
+ var owm OWM
+
+ switch {
+ case opts.Host != "":
+ owm.host = "http://" + opts.Host + "/data/2.5/weather?%s"
+ default:
+ owm.host = baseURL
+ }
+
+ switch opts.Mode {
+ case "JSON", "XML":
+ owm.mode = strings.ToLower(opts.Mode)
+ case "":
+ owm.mode = "json"
+ default:
+ return nil, fmt.Errorf("invalid serialization format: %s", opts.Mode)
+ }
+
+ switch {
+ case validDataUnit(opts.Unit):
+ owm.unit = opts.Unit
+ case opts.Unit == "":
+ owm.unit = "F"
+ default:
+ return nil, fmt.Errorf("invalid unit: %s", opts.Unit)
+ }
+
+ switch {
+ case validLangCode(opts.Lang):
+ owm.lang = opts.Lang
+ case opts.Lang == "":
+ owm.lang = "EN"
+ default:
+ return nil, fmt.Errorf("invalid language code: %s", opts.Lang)
+ }
+
+ switch {
+ case opts.APIKey != "":
+ if validAPIKey(opts.APIKey) {
+ owm.apiKey = opts.APIKey
+ }
+ default:
+ if apiKey := os.Getenv("OWM_API_KEY"); apiKey != "" {
+ if validAPIKey(apiKey) {
+ owm.apiKey = apiKey
+ } else {
+ return nil, errors.New("invalid api key")
+ }
+ } else {
+ return nil, errors.New("an API key is required for use of the OWM api")
+ }
+ }
+
+ switch {
+ case opts.Client != nil:
+ owm.client = opts.Client
+ default:
+ owm.client = http.DefaultClient
+ }
+
+ return &owm, nil
+
}
-// APIError returned on failed API calls.
-type APIError struct {
- Message string `json:"message"`
- COD string `json:"cod"`
+// call
+func (o *OWM) call(url string, payload interface{}) error {
+ res, err := o.client.Get(url)
+ if err != nil {
+ return err
+ }
+ defer res.Body.Close()
+
+ if res.StatusCode != http.StatusOK {
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return err
+ }
+ return errors.New(string(b))
+ }
+
+ switch o.mode {
+ case "json":
+ return json.NewDecoder(res.Body).Decode(payload)
+ case "xml":
+ return xml.NewDecoder(res.Body).Decode(payload)
+ }
+
+ return nil
}
// Coordinates struct holds longitude and latitude data in returned
@@ -112,7 +217,7 @@ type Wind struct {
// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
- ID int `json:"id"`
+ ID int64 `json:"id"`
Main string `json:"main"`
Description string `json:"description"`
Icon string `json:"icon"`
@@ -127,27 +232,19 @@ type Main struct {
Pressure float64 `json:"pressure"`
SeaLevel float64 `json:"sea_level"`
GrndLevel float64 `json:"grnd_level"`
- Humidity int `json:"humidity"`
+ Humidity int64 `json:"humidity"`
+ TempKF float64 `json:"tmep_kf"`
}
// Clouds struct holds data regarding cloud cover.
type Clouds struct {
- All int `json:"all"`
-}
-
-// return key
-// }
-func setKey(key string) (string, error) {
- if err := ValidAPIKey(key); err != nil {
- return "", err
- }
- return key, nil
+ All int64 `json:"all"`
}
-// ValidDataUnit makes sure the string passed in is an accepted
+// validDataUnit makes sure the string passed in is an accepted
// unit of measure to be used for the return data.
-func ValidDataUnit(u string) bool {
- for d := range DataUnits {
+func validDataUnit(u string) bool {
+ for d := range dataUnits {
if u == d {
return true
}
@@ -155,9 +252,9 @@ func ValidDataUnit(u string) bool {
return false
}
-// ValidLangCode makes sure the string passed in is an
+// validLangCode makes sure the string passed in is an
// acceptable lang code.
-func ValidLangCode(c string) bool {
+func validLangCode(c string) bool {
for d := range LangCodes {
if c == d {
return true
@@ -166,10 +263,10 @@ func ValidLangCode(c string) bool {
return false
}
-// ValidDataUnitSymbol makes sure the string passed in is an
+// validDataUnitSymbol makes sure the string passed in is an
// acceptable data unit symbol.
-func ValidDataUnitSymbol(u string) bool {
- for _, d := range DataUnits {
+func validDataUnitSymbol(u string) bool {
+ for _, d := range dataUnits {
if u == d {
return true
}
@@ -177,53 +274,7 @@ func ValidDataUnitSymbol(u string) bool {
return false
}
-// ValidAPIKey makes sure that the key given is a valid one
-func ValidAPIKey(key string) error {
- if len(key) != 32 {
- return errors.New("invalid key")
- }
- return nil
-}
-
-// CheckAPIKeyExists will see if an API key has been set.
-func (c *Config) CheckAPIKeyExists() bool { return len(c.APIKey) > 1 }
-
-// Settings holds the client settings
-type Settings struct {
- client *http.Client
-}
-
-// NewSettings returns a new Setting pointer with default http client.
-func NewSettings() *Settings {
- return &Settings{
- client: http.DefaultClient,
- }
-}
-
-// Optional client settings
-type Option func(s *Settings) error
-
-// WithHttpClient sets custom http client when creating a new Client.
-func WithHttpClient(c *http.Client) Option {
- return func(s *Settings) error {
- if c == nil {
- return errInvalidHttpClient
- }
- s.client = c
- return nil
- }
-}
-
-// setOptions sets Optional client settings to the Settings pointer
-func setOptions(settings *Settings, options []Option) error {
- for _, option := range options {
- if option == nil {
- return errInvalidOption
- }
- err := option(settings)
- if err != nil {
- return err
- }
- }
- return nil
+// validAPIKey makes sure that the key given is a valid one
+func validAPIKey(key string) bool {
+ return len(key) != 33
}
diff --git a/openweathermap_test.go b/openweathermap_test.go
index 824d0ec..37ace40 100644
--- a/openweathermap_test.go
+++ b/openweathermap_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,52 +14,52 @@
package openweathermap
-import (
- "testing"
-)
+// import (
+// "testing"
+// )
-// TestValidDataUnit tests whether or not ValidDataUnit provides
-// the correct assertion on provided data unit.
-func TestValidDataUnit(t *testing.T) {
- for u := range DataUnits {
- if !ValidDataUnit(u) {
- t.Error("False positive on data unit")
- }
- }
+// // TestValidDataUnit tests whether or not ValidDataUnit provides
+// // the correct assertion on provided data unit.
+// func TestValidDataUnit(t *testing.T) {
+// for u := range DataUnits {
+// if !ValidDataUnit(u) {
+// t.Error("False positive on data unit")
+// }
+// }
- if ValidDataUnit("anything") {
- t.Error("Invalid data unit")
- }
-}
+// if ValidDataUnit("anything") {
+// t.Error("Invalid data unit")
+// }
+// }
-func TestDataUnitValues(t *testing.T) {
- for _, s := range DataUnits {
- if !ValidDataUnitSymbol(s) {
- t.Error("False positive on data unit symbol")
- }
- }
+// func TestDataUnitValues(t *testing.T) {
+// for _, s := range DataUnits {
+// if !ValidDataUnitSymbol(s) {
+// t.Error("False positive on data unit symbol")
+// }
+// }
- if ValidDataUnitSymbol("X") {
- t.Error("Invalid data unit symbol")
- }
-}
+// if ValidDataUnitSymbol("X") {
+// t.Error("Invalid data unit symbol")
+// }
+// }
-func TestCheckAPIKeyExists(t *testing.T) {
- c := &Config{
- APIKey: "asdf1234",
- }
+// func TestCheckAPIKeyExists(t *testing.T) {
+// c := &Config{
+// APIKey: "asdf1234",
+// }
- if !c.CheckAPIKeyExists() {
- t.Error("Key not set")
- }
-}
+// if !c.CheckAPIKeyExists() {
+// t.Error("Key not set")
+// }
+// }
-// TestSetOptionsWithEmpty tests setOptions function will do nothing
-// when options are empty.
-func TestSetOptionsWithEmpty(t *testing.T) {
- s := NewSettings()
- err := setOptions(s, nil)
- if err != nil {
- t.Error(err)
- }
-}
+// // TestSetOptionsWithEmpty tests setOptions function will do nothing
+// // when options are empty.
+// func TestSetOptionsWithEmpty(t *testing.T) {
+// s := NewSettings()
+// err := setOptions(s, nil)
+// if err != nil {
+// t.Error(err)
+// }
+// }
diff --git a/pollution.go b/pollution.go
index abb5b2d..7eb7f1a 100644
--- a/pollution.go
+++ b/pollution.go
@@ -1,18 +1,31 @@
+// Copyright 2021 Brian J. Downs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package openweathermap
import (
- "encoding/json"
"fmt"
"strconv"
)
-// DateTimeAliases holds the alias the pollution API supports in lieu
+// dateTimeAliases holds the alias the pollution API supports in lieu.
// of an ISO 8601 timestamp
-var DateTimeAliases = []string{"current"}
+var dateTimeAliases = []string{"current"}
-// ValidAlias checks to make sure the given alias is a valid one
+// ValidAlias checks to make sure the given alias is a valid one.
func ValidAlias(alias string) bool {
- for _, i := range DateTimeAliases {
+ for _, i := range dateTimeAliases {
if i == alias {
return true
}
@@ -20,63 +33,37 @@ func ValidAlias(alias string) bool {
return false
}
-// PollutionData holds the pollution specific data from the call
+// PollutionData holds the pollution specific data from the call.
type PollutionData struct {
Precision float64 `json:"precision"`
Pressure float64 `json:"pressure"`
Value float64 `json:"value"`
}
-// PollutionParameters holds the parameters needed to make
+// PollutionParameters holds the parameters needed to make.
// a call to the pollution API
type PollutionParameters struct {
Location Coordinates
Datetime string // this should be either ISO 8601 or an alias
}
-// Pollution holds the data returnd from the pollution API
+// Pollution holds the data returnd from the pollution API.
type Pollution struct {
Time string `json:"time"`
Location Coordinates `json:"location"`
Data []PollutionData `json:"data"`
- Key string
- *Settings
}
-// NewPollution creates a new reference to Pollution
-func NewPollution(key string, options ...Option) (*Pollution, error) {
- k, err := setKey(key)
- if err != nil {
- return nil, err
- }
- p := &Pollution{
- Key: k,
- Settings: NewSettings(),
- }
+// PollutionByParams gets the pollution data based on the given parameters.
+func (o *OWM) PollutionByParams(params *PollutionParameters) (*Pollution, error) {
+ lat := strconv.FormatFloat(params.Location.Latitude, 'f', -1, 64)
+ lon := strconv.FormatFloat(params.Location.Longitude, 'f', -1, 64)
+ url := fmt.Sprintf("%s%s,%s/%s.json?appid=%s", pollutionURL, lat, lon, params.Datetime, o.apiKey)
- if err := setOptions(p.Settings, options); err != nil {
+ var p Pollution
+ if err := o.call(url, &p); err != nil {
return nil, err
}
- return p, nil
-}
-
-// PollutionByParams gets the pollution data based on the given parameters
-func (p *Pollution) PollutionByParams(params *PollutionParameters) error {
- url := fmt.Sprintf("%s%s,%s/%s.json?appid=%s",
- pollutionURL,
- strconv.FormatFloat(params.Location.Latitude, 'f', -1, 64),
- strconv.FormatFloat(params.Location.Longitude, 'f', -1, 64),
- params.Datetime,
- p.Key)
- response, err := p.client.Get(url)
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- if err = json.NewDecoder(response.Body).Decode(&p); err != nil {
- return err
- }
- return nil
+ return &p, nil
}
diff --git a/pollution_test.go b/pollution_test.go
index 6a61c1a..6b9d0c0 100644
--- a/pollution_test.go
+++ b/pollution_test.go
@@ -1,110 +1,124 @@
+// Copyright 2021 Brian J. Downs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package openweathermap
-import (
- "net/http"
- "os"
- "reflect"
- "testing"
- "time"
-)
-
-// TestNewPollution
-func TestNewPollution(t *testing.T) {
-
- p, err := NewPollution(os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(p).String() != "*openweathermap.Pollution" {
- t.Error("incorrect data type returned")
- }
-}
-
-// TestNewPollution with custom http client
-func TestNewPollutionWithCustomHttpClient(t *testing.T) {
-
- hc := http.DefaultClient
- hc.Timeout = time.Duration(1) * time.Second
- p, err := NewPollution(os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(p).String() != "*openweathermap.Pollution" {
- t.Error("incorrect data type returned")
- }
-
- expected := time.Duration(1) * time.Second
- if p.client.Timeout != expected {
- t.Errorf("Expected Duration %v, but got %v", expected, p.client.Timeout)
- }
-}
-
-// TestNewPollutionWithInvalidOptions will verify that returns an error with
-// invalid option
-func TestNewPollutionWithInvalidOptions(t *testing.T) {
-
- optionsPattern := [][]Option{
- {nil},
- {nil, nil},
- {WithHttpClient(&http.Client{}), nil},
- {nil, WithHttpClient(&http.Client{})},
- }
-
- for _, options := range optionsPattern {
- c, err := NewPollution(os.Getenv("OWM_API_KEY"), options...)
- if err == errInvalidOption {
- t.Logf("Received expected invalid option error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidOption, err)
- }
- if c != nil {
- t.Errorf("Expected nil, but got %v", c)
- }
- }
-}
-
-// TestNewPollutionWithInvalidHttpClient will verify that returns an error with
-// invalid http client
-func TestNewPollutionWithInvalidHttpClient(t *testing.T) {
-
- p, err := NewPollution(os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
- if err == errInvalidHttpClient {
- t.Logf("Received expected bad client error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
- }
- if p != nil {
- t.Errorf("Expected nil, but got %v", p)
- }
-}
-
-func TestValidAlias(t *testing.T) {
- t.Parallel()
- testAliases := []string{"now", "then", "current"}
- for _, i := range testAliases {
- if !ValidAlias(i) {
- t.Log("received expected failure")
- }
- }
-}
-
-// TestPollutionByParams tests the call to the pollution API
-func TestPollutionByParams(t *testing.T) {
- t.Parallel()
- p, err := NewPollution(os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
- params := &PollutionParameters{
- Location: Coordinates{
- Latitude: 0.0,
- Longitude: 10.0,
- },
- Datetime: "current",
- }
- if err := p.PollutionByParams(params); err != nil {
- t.Error(err)
- }
-}
+// import (
+// "net/http"
+// "os"
+// "reflect"
+// "testing"
+// "time"
+// )
+
+// // TestNewPollution
+// func TestNewPollution(t *testing.T) {
+
+// p, err := NewPollution(os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(p).String() != "*openweathermap.Pollution" {
+// t.Error("incorrect data type returned")
+// }
+// }
+
+// // TestNewPollution with custom http client
+// func TestNewPollutionWithCustomHttpClient(t *testing.T) {
+
+// hc := http.DefaultClient
+// hc.Timeout = time.Duration(1) * time.Second
+// p, err := NewPollution(os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(p).String() != "*openweathermap.Pollution" {
+// t.Error("incorrect data type returned")
+// }
+
+// expected := time.Duration(1) * time.Second
+// if p.client.Timeout != expected {
+// t.Errorf("Expected Duration %v, but got %v", expected, p.client.Timeout)
+// }
+// }
+
+// // TestNewPollutionWithInvalidOptions will verify that returns an error with
+// // invalid option
+// func TestNewPollutionWithInvalidOptions(t *testing.T) {
+
+// optionsPattern := [][]Option{
+// {nil},
+// {nil, nil},
+// {WithHttpClient(&http.Client{}), nil},
+// {nil, WithHttpClient(&http.Client{})},
+// }
+
+// for _, options := range optionsPattern {
+// c, err := NewPollution(os.Getenv("OWM_API_KEY"), options...)
+// if err == errInvalidOption {
+// t.Logf("Received expected invalid option error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidOption, err)
+// }
+// if c != nil {
+// t.Errorf("Expected nil, but got %v", c)
+// }
+// }
+// }
+
+// // TestNewPollutionWithInvalidHttpClient will verify that returns an error with
+// // invalid http client
+// func TestNewPollutionWithInvalidHttpClient(t *testing.T) {
+
+// p, err := NewPollution(os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
+// if err == errInvalidHttpClient {
+// t.Logf("Received expected bad client error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
+// }
+// if p != nil {
+// t.Errorf("Expected nil, but got %v", p)
+// }
+// }
+
+// func TestValidAlias(t *testing.T) {
+// t.Parallel()
+// testAliases := []string{"now", "then", "current"}
+// for _, i := range testAliases {
+// if !ValidAlias(i) {
+// t.Log("received expected failure")
+// }
+// }
+// }
+
+// // TestPollutionByParams tests the call to the pollution API
+// func TestPollutionByParams(t *testing.T) {
+// t.Parallel()
+// p, err := NewPollution(os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+// params := &PollutionParameters{
+// Location: Coordinates{
+// Latitude: 0.0,
+// Longitude: 10.0,
+// },
+// Datetime: "current",
+// }
+// if err := p.PollutionByParams(params); err != nil {
+// t.Error(err)
+// }
+// }
diff --git a/road_risk.go b/road_risk.go
new file mode 100644
index 0000000..e0dcb64
--- /dev/null
+++ b/road_risk.go
@@ -0,0 +1,56 @@
+package openweathermap
+
+// RoadRisk
+type RoadRisk struct {
+ Lat float64 `json:"lat"`
+ Lon float64 `json:"lon"`
+ Dt int64 `json:"dt"`
+}
+
+// RoadRiskRequest
+type RoadRiskRequest struct {
+ RoadRisk []RoadRisk `json:"roadrisk"`
+}
+
+// [
+// {
+// "dt": 1602702000,
+// "coord": [
+// 7.27,
+// 44.04
+// ],
+// "weather": {
+// "temp": 278.44,
+// "wind_speed": 2.27,
+// "wind_deg": 7,
+// "precipitation_intensity": 0.38,
+// "dew_point": 276.13
+// },
+// "alerts": [
+// {
+// "sender_name": "METEO-FRANCE",
+// "event": "Moderate thunderstorm warning",
+// "event_level": 2
+// }
+// ]
+// },
+// {
+// "dt": 1602702400,
+// "coord": [
+// 7.37,
+// 45.04
+// ],
+// "weather": {
+// "temp": 282.44,
+// "wind_speed": 1.84,
+// "wind_deg": 316,
+// "dew_point": 275.99
+// },
+// "alerts": [
+
+// ]
+// }
+// ]
+type RoadRiskResponse struct {
+ Alerts []Alert `json:"alerts"`
+}
diff --git a/station.go b/station.go
index 731cf08..e351e36 100644
--- a/station.go
+++ b/station.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import (
"net/url"
)
-// Slice of type string of the valid parameters to be sent from a station.
-// The API refers to this data as the "Weather station data transmission protocol"
+// StationDataParameters is a slice of valid parameters to be sent from a station.
+// The API refers to this data as the "Weather station data transmission protocol".
var StationDataParameters = []string{
"wind_dir", // Wind direction
"wind_speed", // Wind speed
diff --git a/station_test.go b/station_test.go
index 64e5a5b..dde4e44 100644
--- a/station_test.go
+++ b/station_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 Brian J. Downs
+// Copyright 2021 Brian J. Downs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@ package openweathermap
import (
"reflect"
+ "strconv"
"testing"
)
@@ -46,11 +47,11 @@ func TestValidateStationDataParameter(t *testing.T) {
func TestConvertToURLValues(t *testing.T) {
t.Parallel()
- var count = 1
- var urlData = make(map[string]string)
+ count := 1
+ urlData := make(map[string]string)
for _, s := range StationDataParameters {
- urlData[s] = string(count)
+ urlData[s] = strconv.Itoa(count)
count++
}
diff --git a/uv.go b/uv.go
index 2b10b9d..f5479e9 100644
--- a/uv.go
+++ b/uv.go
@@ -1,79 +1,61 @@
+// Copyright 2021 Brian J. Downs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package openweathermap
import (
- "encoding/json"
"errors"
"fmt"
"time"
)
-var errInvalidUVIndex = errors.New("invalid UV index value")
-
-// UVDataPoints holds the UV specific data
+// UVDataPoints holds the UV specific data.
type UVDataPoints struct {
DT int64 `json:"dt"`
Value float64 `json:"value"`
}
-// UV contains the response from the OWM UV API
+// UV contains the response from the OWM UV API.
type UV struct {
- Coord []float64 `json:"coord"`
- Data []UVDataPoints `json:"data,omitempty"`
- /*Data []struct {
- DT int64 `json:"dt"`
- Value float64 `json:"value"`
- } `json:"data,omitempty"`*/
- DT int64 `json:"dt,omitempty"`
- Value float64 `json:"value,omitempty"`
- Key string
- *Settings
+ Coordinates
+ DateISO string `json:"date_iso"`
+ Date int64 `json:"date,omitempty"`
+ Value float64 `json:"value,omitempty"`
}
-// NewUV creates a new reference to UV
-func NewUV(key string, options ...Option) (*UV, error) {
- k, err := setKey(key)
- if err != nil {
- return nil, err
- }
- u := &UV{
- Key: k,
- Settings: NewSettings(),
- }
+// UVCurrent gets the current UV data for the given coordinates.
+func (o *OWM) UVCurrent(coord *Coordinates) (*UV, error) {
+ url := fmt.Sprintf("%suvi?lat=%f&lon=%f&appid=%s", uvURL, coord.Latitude, coord.Longitude, o.apiKey)
- if err := setOptions(u.Settings, options); err != nil {
+ var uv UV
+ if err := o.call(url, &uv); err != nil {
return nil, err
}
- return u, nil
-}
-
-// Current gets the current UV data for the given coordinates
-func (u *UV) Current(coord *Coordinates) error {
- response, err := u.client.Get(fmt.Sprintf("%suvi?lat=%f&lon=%f&appid=%s", uvURL, coord.Latitude, coord.Longitude, u.Key))
- if err != nil {
- return err
- }
- defer response.Body.Close()
-
- if err = json.NewDecoder(response.Body).Decode(&u); err != nil {
- return err
- }
- return nil
+ return &uv, nil
}
-// Historical gets the historical UV data for the coordinates and times
-func (u *UV) Historical(coord *Coordinates, start, end time.Time) error {
- response, err := u.client.Get(fmt.Sprintf("%shistory?lat=%f&lon=%f&start=%d&end=%d&appid=%s", uvURL, coord.Latitude, coord.Longitude, start.Unix(), end.Unix(), u.Key))
- if err != nil {
- return err
- }
- defer response.Body.Close()
+// UVHistorical gets the historical UV data for the coordinates and times.
+func (o *OWM) UVHistorical(coord *Coordinates, start, end time.Time) (*UV, error) {
+ url := fmt.Sprintf("%shistory?lat=%f&lon=%f&start=%d&end=%d&appid=%s", uvURL, coord.Latitude, coord.Longitude, start.Unix(), end.Unix(), o.apiKey)
- if err = json.NewDecoder(response.Body).Decode(&u); err != nil {
- return err
+ var uv UV
+ if err := o.call(url, &uv); err != nil {
+ return nil, err
}
- return nil
+ return &uv, nil
}
// UVIndexInfo
@@ -92,36 +74,36 @@ type UVIndexInfo struct {
RecommendedProtection string
}
-// UVData contains data in regards to UV index ranges, rankings, and steps for protection
+// UVData contains data in regards to UV index ranges, rankings, and steps for protection.
var UVData = []UVIndexInfo{
{
- UVIndex: []float64{0, 2.9},
- MGC: "Green",
- Risk: "Low",
+ UVIndex: []float64{0, 2.9},
+ MGC: "Green",
+ Risk: "Low",
RecommendedProtection: "Wear sunglasses on bright days; use sunscreen if there is snow on the ground, which reflects UV radiation, or if you have particularly fair skin.",
},
{
- UVIndex: []float64{3, 5.9},
- MGC: "Yellow",
- Risk: "Moderate",
+ UVIndex: []float64{3, 5.9},
+ MGC: "Yellow",
+ Risk: "Moderate",
RecommendedProtection: "Take precautions, such as covering up, if you will be outside. Stay in shade near midday when the sun is strongest.",
},
{
- UVIndex: []float64{6, 7.9},
- MGC: "Orange",
- Risk: "High",
+ UVIndex: []float64{6, 7.9},
+ MGC: "Orange",
+ Risk: "High",
RecommendedProtection: "Cover the body with sun protective clothing, use SPF 30+ sunscreen, wear a hat, reduce time in the sun within three hours of solar noon, and wear sunglasses.",
},
{
- UVIndex: []float64{8, 10.9},
- MGC: "Red",
- Risk: "Very high",
+ UVIndex: []float64{8, 10.9},
+ MGC: "Red",
+ Risk: "Very high",
RecommendedProtection: "Wear SPF 30+ sunscreen, a shirt, sunglasses, and a wide-brimmed hat. Do not stay in the sun for too long.",
},
{
- UVIndex: []float64{11},
- MGC: "Violet",
- Risk: "Extreme",
+ UVIndex: []float64{11},
+ MGC: "Violet",
+ Risk: "Extreme",
RecommendedProtection: "Take all precautions: Wear SPF 30+ sunscreen, a long-sleeved shirt and trousers, sunglasses, and a very broad hat. Avoid the sun within three hours of solar noon.",
},
}
@@ -143,26 +125,7 @@ func (u *UV) UVInformation() ([]UVIndexInfo, error) {
case u.Value >= 11:
return []UVIndexInfo{UVData[4]}, nil
default:
- return nil, errInvalidUVIndex
- }
-
- case len(u.Data) > 0:
- var uvi []UVIndexInfo
- for _, i := range u.Data {
- switch {
- case i.Value < 2.9:
- uvi = append(uvi, UVData[0])
- case i.Value > 3 && u.Value < 5.9:
- uvi = append(uvi, UVData[1])
- case i.Value > 6 && u.Value < 7.9:
- uvi = append(uvi, UVData[2])
- case i.Value > 8 && u.Value < 10.9:
- uvi = append(uvi, UVData[3])
- case i.Value >= 11:
- uvi = append(uvi, UVData[4])
- default:
- return nil, errInvalidUVIndex
- }
+ return nil, errors.New("invalid UV index value")
}
}
diff --git a/uv_test.go b/uv_test.go
index 75ef0ff..3ed60c6 100644
--- a/uv_test.go
+++ b/uv_test.go
@@ -1,140 +1,154 @@
+// Copyright 2021 Brian J. Downs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package openweathermap
-import (
- "net/http"
- "os"
- "reflect"
- "testing"
- "time"
-)
-
-var coords = &Coordinates{
- Longitude: 53.343497,
- Latitude: -6.288379,
-}
-
-// TestNewUV
-func TestNewUV(t *testing.T) {
-
- uv, err := NewUV(os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
- t.Error("incorrect data type returned")
- }
-}
-
-// TestNewUV with custom http client
-func TestNewUVWithCustomHttpClient(t *testing.T) {
-
- hc := http.DefaultClient
- hc.Timeout = time.Duration(1) * time.Second
- uv, err := NewUV(os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
- if err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
- t.Error("incorrect data type returned")
- }
-
- expected := time.Duration(1) * time.Second
- if uv.client.Timeout != expected {
- t.Errorf("Expected Duration %v, but got %v", expected, uv.client.Timeout)
- }
-}
-
-// TestNewUVWithInvalidOptions will verify that returns an error with
-// invalid option
-func TestNewUVWithInvalidOptions(t *testing.T) {
-
- optionsPattern := [][]Option{
- {nil},
- {nil, nil},
- {WithHttpClient(&http.Client{}), nil},
- {nil, WithHttpClient(&http.Client{})},
- }
-
- for _, options := range optionsPattern {
- c, err := NewUV(os.Getenv("OWM_API_KEY"), options...)
- if err == errInvalidOption {
- t.Logf("Received expected invalid option error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidOption, err)
- }
- if c != nil {
- t.Errorf("Expected nil, but got %v", c)
- }
- }
-}
-
-// TestNewUVWithInvalidHttpClient will verify that returns an error with
-// invalid http client
-func TestNewUVWithInvalidHttpClient(t *testing.T) {
-
- uv, err := NewUV(os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
- if err == errInvalidHttpClient {
- t.Logf("Received expected bad client error. message: %s", err.Error())
- } else if err != nil {
- t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
- }
- if uv != nil {
- t.Errorf("Expected nil, but got %v", uv)
- }
-}
-
-// TestCurrentUV
-func TestCurrentUV(t *testing.T) {
- t.Parallel()
-
- uv, err := NewUV(os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- if err := uv.Current(coords); err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
- t.Error("incorrect data type returned")
- }
-}
-
-// TestHistoricalUV
-func TestHistoricalUV(t *testing.T) {
- t.Parallel()
-
- /* uv := NewUV(os.Getenv("OWM_API_KEY"))
-
- end := time.Now().UTC()
- start := time.Now().UTC().Add(-time.Hour * time.Duration(24))
-
- if err := uv.Historical(coords, start, end); err != nil {
- t.Error(err)
- }
-
- if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
- t.Error("incorrect data type returned")
- }*/
-}
-
-func TestUVInformation(t *testing.T) {
- t.Parallel()
-
- uv, err := NewUV(os.Getenv("OWM_API_KEY"))
- if err != nil {
- t.Error(err)
- }
-
- if err := uv.Current(coords); err != nil {
- t.Error(err)
- }
-
- _, err = uv.UVInformation()
- if err != nil {
- t.Error(err)
- }
-}
+// import (
+// "net/http"
+// "os"
+// "reflect"
+// "testing"
+// "time"
+// )
+
+// var coords = &Coordinates{
+// Longitude: 53.343497,
+// Latitude: -6.288379,
+// }
+
+// // TestNewUV
+// func TestNewUV(t *testing.T) {
+
+// uv, err := NewUV(os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
+// t.Error("incorrect data type returned")
+// }
+// }
+
+// // TestNewUV with custom http client
+// func TestNewUVWithCustomHttpClient(t *testing.T) {
+
+// hc := http.DefaultClient
+// hc.Timeout = time.Duration(1) * time.Second
+// uv, err := NewUV(os.Getenv("OWM_API_KEY"), WithHttpClient(hc))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
+// t.Error("incorrect data type returned")
+// }
+
+// expected := time.Duration(1) * time.Second
+// if uv.client.Timeout != expected {
+// t.Errorf("Expected Duration %v, but got %v", expected, uv.client.Timeout)
+// }
+// }
+
+// // TestNewUVWithInvalidOptions will verify that returns an error with
+// // invalid option
+// func TestNewUVWithInvalidOptions(t *testing.T) {
+
+// optionsPattern := [][]Option{
+// {nil},
+// {nil, nil},
+// {WithHttpClient(&http.Client{}), nil},
+// {nil, WithHttpClient(&http.Client{})},
+// }
+
+// for _, options := range optionsPattern {
+// c, err := NewUV(os.Getenv("OWM_API_KEY"), options...)
+// if err == errInvalidOption {
+// t.Logf("Received expected invalid option error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidOption, err)
+// }
+// if c != nil {
+// t.Errorf("Expected nil, but got %v", c)
+// }
+// }
+// }
+
+// // TestNewUVWithInvalidHttpClient will verify that returns an error with
+// // invalid http client
+// func TestNewUVWithInvalidHttpClient(t *testing.T) {
+
+// uv, err := NewUV(os.Getenv("OWM_API_KEY"), WithHttpClient(nil))
+// if err == errInvalidHttpClient {
+// t.Logf("Received expected bad client error. message: %s", err.Error())
+// } else if err != nil {
+// t.Errorf("Expected %v, but got %v", errInvalidHttpClient, err)
+// }
+// if uv != nil {
+// t.Errorf("Expected nil, but got %v", uv)
+// }
+// }
+
+// // TestCurrentUV
+// func TestCurrentUV(t *testing.T) {
+// t.Parallel()
+
+// uv, err := NewUV(os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if err := uv.Current(coords); err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
+// t.Error("incorrect data type returned")
+// }
+// }
+
+// // TestHistoricalUV
+// func TestHistoricalUV(t *testing.T) {
+// t.Parallel()
+
+// /* uv := NewUV(os.Getenv("OWM_API_KEY"))
+
+// end := time.Now().UTC()
+// start := time.Now().UTC().Add(-time.Hour * time.Duration(24))
+
+// if err := uv.Historical(coords, start, end); err != nil {
+// t.Error(err)
+// }
+
+// if reflect.TypeOf(uv).String() != "*openweathermap.UV" {
+// t.Error("incorrect data type returned")
+// }*/
+// }
+
+// func TestUVInformation(t *testing.T) {
+// t.Parallel()
+
+// uv, err := NewUV(os.Getenv("OWM_API_KEY"))
+// if err != nil {
+// t.Error(err)
+// }
+
+// if err := uv.Current(coords); err != nil {
+// t.Error(err)
+// }
+
+// _, err = uv.UVInformation()
+// if err != nil {
+// t.Error(err)
+// }
+// }