From 8e31b50d95e44f545af3832b16fd0b713058dc50 Mon Sep 17 00:00:00 2001 From: Derek Garnett Date: Tue, 5 Nov 2024 17:07:30 -0600 Subject: [PATCH] Add OneCallTimeMachine function (#113) * Add OneCallTimeMachine function * Make date make more sense --- current.go | 36 ++++++++++++++++---------------- history.go | 2 +- onecall.go | 52 ++++++++++++++++++++++++++++++++++++++--------- onecall_test.go | 20 ++++++++++++++++++ openweathermap.go | 2 +- station_test.go | 3 ++- uv.go | 30 +++++++++++++-------------- 7 files changed, 99 insertions(+), 46 deletions(-) diff --git a/current.go b/current.go index cdce0be..66390c6 100644 --- a/current.go +++ b/current.go @@ -25,24 +25,24 @@ import ( // CurrentWeatherData struct contains an aggregate view of the structs // defined above for JSON to be unmarshaled into. type CurrentWeatherData struct { - GeoPos Coordinates `json:"coord"` - Sys Sys `json:"sys"` - Base string `json:"base"` - Weather []Weather `json:"weather"` - Main Main `json:"main"` - Visibility int `json:"visibility"` - Wind Wind `json:"wind"` - Clouds Clouds `json:"clouds"` - Rain Rain `json:"rain"` - Snow Snow `json:"snow"` - Dt int `json:"dt"` - ID int `json:"id"` - Name string `json:"name"` - Cod int `json:"cod"` - Timezone int `json:"timezone"` - Unit string - Lang string - Key string + GeoPos Coordinates `json:"coord"` + Sys Sys `json:"sys"` + Base string `json:"base"` + Weather []Weather `json:"weather"` + Main Main `json:"main"` + Visibility int `json:"visibility"` + Wind Wind `json:"wind"` + Clouds Clouds `json:"clouds"` + Rain Rain `json:"rain"` + Snow Snow `json:"snow"` + Dt int `json:"dt"` + ID int `json:"id"` + Name string `json:"name"` + Cod int `json:"cod"` + Timezone int `json:"timezone"` + Unit string + Lang string + Key string *Settings } diff --git a/history.go b/history.go index 7ec66c6..f37d8d3 100644 --- a/history.go +++ b/history.go @@ -68,7 +68,7 @@ type HistoricalWeatherData struct { } // NewHistorical returns a new HistoricalWeatherData pointer with -//the supplied arguments. +// the supplied arguments. func NewHistorical(unit, key string, options ...Option) (*HistoricalWeatherData, error) { h := &HistoricalWeatherData{ Settings: NewSettings(), diff --git a/onecall.go b/onecall.go index 0db90c0..8bf5bb4 100644 --- a/onecall.go +++ b/onecall.go @@ -17,20 +17,22 @@ import ( "encoding/json" "fmt" "strings" + "time" ) // OneCallData struct contains an aggregate view of the structs // defined above for JSON to be unmarshaled into. type OneCallData struct { - Latitude float64 `json:"lat"` - Longitude float64 `json:"lon"` - Timezone string `json:"timezone"` - TimezoneOffset int `json:"timezone_offset"` - Current OneCallCurrentData `json:"current,omitempty"` - Minutely []OneCallMinutelyData `json:"minutely,omitempty"` - Hourly []OneCallHourlyData `json:"hourly,omitempty"` - Daily []OneCallDailyData `json:"daily,omitempty"` - Alerts []OneCallAlertData `json:"alerts,omitempty"` + Latitude float64 `json:"lat"` + Longitude float64 `json:"lon"` + Timezone string `json:"timezone"` + TimezoneOffset int `json:"timezone_offset"` + Current OneCallCurrentData `json:"current,omitempty"` + Minutely []OneCallMinutelyData `json:"minutely,omitempty"` + Hourly []OneCallHourlyData `json:"hourly,omitempty"` + Daily []OneCallDailyData `json:"daily,omitempty"` + Alerts []OneCallAlertData `json:"alerts,omitempty"` + Data []OneCallTimeMachineData `json:"data,omitempty"` Unit string Lang string @@ -39,6 +41,24 @@ type OneCallData struct { *Settings } +type OneCallTimeMachineData struct { + Dt int `json:"dt"` + Sunrise int `json:"sunrise"` + Sunset int `json:"sunset"` + Temp float64 `json:"temp"` + FeelsLike float64 `json:"feels_like"` + Pressure int `json:"pressure"` + Humidity int `json:"humidity"` + DewPoint float64 `json:"dew_point"` + Clouds int `json:"clouds"` + UVI float64 `json:"uvi"` + Visibility int `json:"visibility"` + WindSpeed float64 `json:"wind_speed"` + WindGust float64 `json:"wind_gust,omitempty"` + WindDeg float64 `json:"wind_deg"` + Weather []Weather `json:"weather"` +} + type OneCallCurrentData struct { Dt int `json:"dt"` Sunrise int `json:"sunrise"` @@ -161,7 +181,19 @@ func NewOneCall(unit, lang, key string, excludes []string, options ...Option) (* // OneCallByCoordinates will provide the onecall weather with the // provided location coordinates. func (w *OneCallData) OneCallByCoordinates(location *Coordinates) error { - response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(onecallURL, "appid=%s&lat=%f&lon=%f&units=%s&lang=%s&exclude=%s"), w.Key, location.Latitude, location.Longitude, w.Unit, w.Lang, w.Excludes)) + response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(onecallURL, "?appid=%s&lat=%f&lon=%f&units=%s&lang=%s&exclude=%s"), w.Key, location.Latitude, location.Longitude, w.Unit, w.Lang, w.Excludes)) + if err != nil { + return err + } + defer response.Body.Close() + + return json.NewDecoder(response.Body).Decode(&w) +} + +// OneCallTimeMachine will provide the onecall timemachine weather with the +// provided location coordinates and unix timestamp +func (w *OneCallData) OneCallTimeMachine(location *Coordinates, datetime time.Time) error { + response, err := w.client.Get(fmt.Sprintf(fmt.Sprintf(onecallURL, "timemachine?appid=%s&lat=%f&lon=%f&units=%s&lang=%s&dt=%d"), w.Key, location.Latitude, location.Longitude, w.Unit, w.Lang, datetime.Unix())) if err != nil { return err } diff --git a/onecall_test.go b/onecall_test.go index 08e0e51..e173b9d 100644 --- a/onecall_test.go +++ b/onecall_test.go @@ -166,3 +166,23 @@ func TestNewOneCallWithTwoExcludes(t *testing.T) { t.Error("exclude alerts and daily fails") } } + +// TestOneCallTimeMachine will verify that onecall data can be retrieved for a +// given set of coordinates and a time +func TestOneCallTimeMachine(t *testing.T) { + t.Parallel() + c, err := NewOneCall("f", "DE", os.Getenv("OWM_API_KEY"), []string{}) + if err != nil { + t.Error("Error creating instance of OneCallData") + } + err = c.OneCallTimeMachine( + &Coordinates{ + Longitude: -112.07, + Latitude: 33.45, + }, + time.Now().AddDate(0, 0, -1), + ) + if err != nil { + t.Error(err) + } +} diff --git a/openweathermap.go b/openweathermap.go index 5d2f376..72415fe 100644 --- a/openweathermap.go +++ b/openweathermap.go @@ -35,7 +35,7 @@ var ( var DataUnits = map[string]string{"C": "metric", "F": "imperial", "K": "internal"} var ( baseURL = "https://api.openweathermap.org/data/2.5/weather?%s" - onecallURL = "https://api.openweathermap.org/data/3.0/onecall?%s" + onecallURL = "https://api.openweathermap.org/data/3.0/onecall/%s" iconURL = "https://openweathermap.org/img/w/%s" groupURL = "http://api.openweathermap.org/data/2.5/group?%s" stationURL = "https://api.openweathermap.org/data/2.5/station?id=%d" diff --git a/station_test.go b/station_test.go index 578b1f5..19408aa 100644 --- a/station_test.go +++ b/station_test.go @@ -15,6 +15,7 @@ package openweathermap import ( + "fmt" "reflect" "testing" ) @@ -50,7 +51,7 @@ func TestConvertToURLValues(t *testing.T) { var urlData = make(map[string]string) for _, s := range StationDataParameters { - urlData[s] = string(count) + urlData[s] = fmt.Sprint(count) count++ } diff --git a/uv.go b/uv.go index f298e62..932dfa3 100644 --- a/uv.go +++ b/uv.go @@ -106,33 +106,33 @@ type UVIndexInfo struct { // 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.", }, }