mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2024-11-09 20:44:03 -08:00
feat: update Open Weather Map to use Geocoding API
Updated the Open Weather Map Current Weather URL to remove the deprecated query parameter. Updated the URL to add the supported latitude and longitude parameters. Added a call to the Open Wetaher Map Geocoding API to resolve the location parameter to latitude and longitude values as specified in the Open Weather Map documentation. Added properties to the Open Weather Map segment to allow users to manually specify the latitude and longitude if desired. Doing this will skip the geocoding API call and ignore the location parameter. Updated the website documentation for the Open Weather Map segment to reflect the property changes and explain how to use them.
This commit is contained in:
parent
1ca3a8d256
commit
ed8d89a7cc
|
@ -28,6 +28,10 @@ const (
|
||||||
Location properties.Property = "location"
|
Location properties.Property = "location"
|
||||||
// Units openweathermap units
|
// Units openweathermap units
|
||||||
Units properties.Property = "units"
|
Units properties.Property = "units"
|
||||||
|
// Latitude for the location used in place of location
|
||||||
|
Latitude properties.Property = "latitude"
|
||||||
|
// Longitude for the location used in place of location
|
||||||
|
Longitude properties.Property = "longitude"
|
||||||
// CacheKeyResponse key used when caching the response
|
// CacheKeyResponse key used when caching the response
|
||||||
CacheKeyResponse string = "owm_response"
|
CacheKeyResponse string = "owm_response"
|
||||||
// CacheKeyURL key used when caching the url responsible for the response
|
// CacheKeyURL key used when caching the url responsible for the response
|
||||||
|
@ -48,6 +52,11 @@ type owmDataResponse struct {
|
||||||
temperature `json:"main"`
|
temperature `json:"main"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type geoLocation struct {
|
||||||
|
Lat float64 `json:"lat"`
|
||||||
|
Lon float64 `json:"lon"`
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Owm) Enabled() bool {
|
func (d *Owm) Enabled() bool {
|
||||||
err := d.setStatus()
|
err := d.setStatus()
|
||||||
return err == nil
|
return err == nil
|
||||||
|
@ -76,9 +85,28 @@ func (d *Owm) getResult() (*owmDataResponse, error) {
|
||||||
|
|
||||||
apikey := d.props.GetString(APIKey, ".")
|
apikey := d.props.GetString(APIKey, ".")
|
||||||
location := d.props.GetString(Location, "De Bilt,NL")
|
location := d.props.GetString(Location, "De Bilt,NL")
|
||||||
|
latitude := d.props.GetFloat64(Latitude, 91)
|
||||||
|
longitude := d.props.GetFloat64(Longitude, 181)
|
||||||
units := d.props.GetString(Units, "standard")
|
units := d.props.GetString(Units, "standard")
|
||||||
httpTimeout := d.props.GetInt(properties.HTTPTimeout, properties.DefaultHTTPTimeout)
|
httpTimeout := d.props.GetInt(properties.HTTPTimeout, properties.DefaultHTTPTimeout)
|
||||||
d.URL = fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", location, units, apikey)
|
|
||||||
|
if latitude > 90 || latitude < -90 || longitude > 180 && longitude < -180 {
|
||||||
|
var geoResponse []geoLocation
|
||||||
|
geocodingURL := fmt.Sprintf("http://api.openweathermap.org/geo/1.0/direct?q=%s&limit=1&appid=%s", location, apikey)
|
||||||
|
body, err := d.env.HTTPRequest(geocodingURL, nil, httpTimeout)
|
||||||
|
if err != nil {
|
||||||
|
return new(owmDataResponse), err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &geoResponse)
|
||||||
|
if err != nil {
|
||||||
|
return new(owmDataResponse), err
|
||||||
|
}
|
||||||
|
|
||||||
|
latitude = geoResponse[0].Lat
|
||||||
|
longitude = geoResponse[0].Lon
|
||||||
|
}
|
||||||
|
|
||||||
|
d.URL = fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?lat=%v&lon=%v&units=%s&appid=%s", latitude, longitude, units, apikey)
|
||||||
|
|
||||||
body, err := d.env.HTTPRequest(d.URL, nil, httpTimeout)
|
body, err := d.env.HTTPRequest(d.URL, nil, httpTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,56 +12,107 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
OWMAPIURL = "http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key"
|
OWMGEOAPIURL = "http://api.openweathermap.org/geo/1.0/direct?q=AMSTERDAM,NL&limit=1&appid=key"
|
||||||
|
OWMWEATHERAPIURL = "http://api.openweathermap.org/data/2.5/weather?lat=52.3727598&lon=4.8936041&units=metric&appid=key"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOWMSegmentSingle(t *testing.T) {
|
func TestOWMSegmentSingle(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Case string
|
Case string
|
||||||
JSONResponse string
|
Location string
|
||||||
ExpectedString string
|
Latitude float64
|
||||||
ExpectedEnabled bool
|
Longitude float64
|
||||||
Template string
|
GeoJSONResponse string
|
||||||
Error error
|
WeatherJSONResponse string
|
||||||
|
ExpectedString string
|
||||||
|
ExpectedEnabled bool
|
||||||
|
Template string
|
||||||
|
Error error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Case: "Sunny Display",
|
Case: "Sunny Display",
|
||||||
JSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
Location: "AMSTERDAM,NL",
|
||||||
ExpectedString: "\ue30d (20°C)",
|
GeoJSONResponse: `[{"lat": 52.3727598,"lon": 4.8936041}]`,
|
||||||
ExpectedEnabled: true,
|
WeatherJSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
||||||
|
ExpectedString: "\ue30d (20°C)",
|
||||||
|
ExpectedEnabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "Sunny Display",
|
Case: "Sunny Display",
|
||||||
JSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
Location: "AMSTERDAM,NL",
|
||||||
ExpectedString: "\ue30d (20°C)",
|
GeoJSONResponse: `[{"lat": 52.3727598,"lon": 4.8936041}]`,
|
||||||
ExpectedEnabled: true,
|
WeatherJSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
||||||
Template: "{{.Weather}} ({{.Temperature}}{{.UnitIcon}})",
|
ExpectedString: "\ue30d (20°C)",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
Template: "{{.Weather}} ({{.Temperature}}{{.UnitIcon}})",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "Sunny Display",
|
Case: "Sunny Display",
|
||||||
JSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
Location: "AMSTERDAM,NL",
|
||||||
ExpectedString: "\ue30d",
|
GeoJSONResponse: `[{"lat": 52.3727598,"lon": 4.8936041}]`,
|
||||||
ExpectedEnabled: true,
|
WeatherJSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
||||||
Template: "{{.Weather}} ",
|
ExpectedString: "\ue30d",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
Template: "{{.Weather}} ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Case: "Error in retrieving data",
|
Case: "Config Skip Geocoding Check With Location",
|
||||||
JSONResponse: "nonsense",
|
Location: "AMSTERDAM,NL",
|
||||||
Error: errors.New("Something went wrong"),
|
Latitude: 52.3727598,
|
||||||
ExpectedEnabled: false,
|
Longitude: 4.8936041,
|
||||||
|
WeatherJSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
||||||
|
ExpectedString: "\ue30d (20°C)",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Config Skip Geocoding Check Without Location",
|
||||||
|
Latitude: 52.3727598,
|
||||||
|
Longitude: 4.8936041,
|
||||||
|
WeatherJSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
|
||||||
|
ExpectedString: "\ue30d (20°C)",
|
||||||
|
ExpectedEnabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Error in retrieving data",
|
||||||
|
Location: "AMSTERDAM,NL",
|
||||||
|
GeoJSONResponse: "nonsense",
|
||||||
|
WeatherJSONResponse: "nonsense",
|
||||||
|
Error: errors.New("Something went wrong"),
|
||||||
|
ExpectedEnabled: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := &mock.MockedEnvironment{}
|
env := &mock.MockedEnvironment{}
|
||||||
props := properties.Map{
|
var props properties.Map
|
||||||
APIKey: "key",
|
if tc.Latitude != 0 && tc.Longitude != 0 && tc.Location != "" {
|
||||||
Location: "AMSTERDAM,NL",
|
props = properties.Map{
|
||||||
Units: "metric",
|
APIKey: "key",
|
||||||
properties.CacheTimeout: 0,
|
Location: tc.Location,
|
||||||
|
Latitude: tc.Latitude,
|
||||||
|
Longitude: tc.Longitude,
|
||||||
|
Units: "metric",
|
||||||
|
properties.CacheTimeout: 0,
|
||||||
|
}
|
||||||
|
} else if tc.Location != "" {
|
||||||
|
props = properties.Map{
|
||||||
|
APIKey: "key",
|
||||||
|
Location: tc.Location,
|
||||||
|
Units: "metric",
|
||||||
|
properties.CacheTimeout: 0,
|
||||||
|
}
|
||||||
|
} else if tc.Latitude != 0 && tc.Longitude != 0 {
|
||||||
|
props = properties.Map{
|
||||||
|
APIKey: "key",
|
||||||
|
Latitude: tc.Latitude,
|
||||||
|
Longitude: tc.Longitude,
|
||||||
|
Units: "metric",
|
||||||
|
properties.CacheTimeout: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env.On("HTTPRequest", OWMAPIURL).Return([]byte(tc.JSONResponse), tc.Error)
|
env.On("HTTPRequest", OWMGEOAPIURL).Return([]byte(tc.GeoJSONResponse), tc.Error)
|
||||||
|
env.On("HTTPRequest", OWMWEATHERAPIURL).Return([]byte(tc.WeatherJSONResponse), tc.Error)
|
||||||
|
|
||||||
o := &Owm{
|
o := &Owm{
|
||||||
props: props,
|
props: props,
|
||||||
|
@ -179,14 +230,16 @@ func TestOWMSegmentIcons(t *testing.T) {
|
||||||
ExpectedIconString: "\ue313",
|
ExpectedIconString: "\ue313",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
geoResponse := `[{"lat": 52.3727598,"lon": 4.8936041}]`
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := &mock.MockedEnvironment{}
|
env := &mock.MockedEnvironment{}
|
||||||
|
|
||||||
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20.3}}`, tc.IconID)
|
weatherResponse := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20.3}}`, tc.IconID)
|
||||||
expectedString := fmt.Sprintf("%s (20°C)", tc.ExpectedIconString)
|
expectedString := fmt.Sprintf("%s (20°C)", tc.ExpectedIconString)
|
||||||
|
|
||||||
env.On("HTTPRequest", OWMAPIURL).Return([]byte(response), nil)
|
env.On("HTTPRequest", OWMGEOAPIURL).Return([]byte(geoResponse), nil)
|
||||||
|
env.On("HTTPRequest", OWMWEATHERAPIURL).Return([]byte(weatherResponse), nil)
|
||||||
|
|
||||||
o := &Owm{
|
o := &Owm{
|
||||||
props: properties.Map{
|
props: properties.Map{
|
||||||
|
@ -206,10 +259,11 @@ func TestOWMSegmentIcons(t *testing.T) {
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := &mock.MockedEnvironment{}
|
env := &mock.MockedEnvironment{}
|
||||||
|
|
||||||
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20.3}}`, tc.IconID)
|
weatherResponse := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20.3}}`, tc.IconID)
|
||||||
expectedString := fmt.Sprintf("«%s (20°C)»(http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key)", tc.ExpectedIconString)
|
expectedString := fmt.Sprintf("«%s (20°C)»(http://api.openweathermap.org/data/2.5/weather?lat=52.3727598&lon=4.8936041&units=metric&appid=key)", tc.ExpectedIconString)
|
||||||
|
|
||||||
env.On("HTTPRequest", OWMAPIURL).Return([]byte(response), nil)
|
env.On("HTTPRequest", OWMGEOAPIURL).Return([]byte(geoResponse), nil)
|
||||||
|
env.On("HTTPRequest", OWMWEATHERAPIURL).Return([]byte(weatherResponse), nil)
|
||||||
|
|
||||||
o := &Owm{
|
o := &Owm{
|
||||||
props: properties.Map{
|
props: properties.Map{
|
||||||
|
@ -240,7 +294,7 @@ func TestOWMSegmentFromCache(t *testing.T) {
|
||||||
env: env,
|
env: env,
|
||||||
}
|
}
|
||||||
cache.On("Get", "owm_response").Return(response, true)
|
cache.On("Get", "owm_response").Return(response, true)
|
||||||
cache.On("Get", "owm_url").Return("http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key", true)
|
cache.On("Get", "owm_url").Return("http://api.openweathermap.org/data/2.5/weather?lat=52.3727598&lon=4.8936041&units=metric&appid=key", true)
|
||||||
cache.On("Set").Return()
|
cache.On("Set").Return()
|
||||||
env.On("Cache").Return(cache)
|
env.On("Cache").Return(cache)
|
||||||
|
|
||||||
|
@ -250,7 +304,7 @@ func TestOWMSegmentFromCache(t *testing.T) {
|
||||||
|
|
||||||
func TestOWMSegmentFromCacheWithHyperlink(t *testing.T) {
|
func TestOWMSegmentFromCacheWithHyperlink(t *testing.T) {
|
||||||
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d")
|
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d")
|
||||||
expectedString := fmt.Sprintf("«%s (20°C)»(http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key)", "\ue30d")
|
expectedString := fmt.Sprintf("«%s (20°C)»(http://api.openweathermap.org/data/2.5/weather?lat=52.3727598&lon=4.8936041&units=metric&appid=key)", "\ue30d")
|
||||||
|
|
||||||
env := &mock.MockedEnvironment{}
|
env := &mock.MockedEnvironment{}
|
||||||
cache := &mock.MockedCache{}
|
cache := &mock.MockedCache{}
|
||||||
|
@ -264,7 +318,7 @@ func TestOWMSegmentFromCacheWithHyperlink(t *testing.T) {
|
||||||
env: env,
|
env: env,
|
||||||
}
|
}
|
||||||
cache.On("Get", "owm_response").Return(response, true)
|
cache.On("Get", "owm_response").Return(response, true)
|
||||||
cache.On("Get", "owm_url").Return("http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key", true)
|
cache.On("Get", "owm_url").Return("http://api.openweathermap.org/data/2.5/weather?lat=52.3727598&lon=4.8936041&units=metric&appid=key", true)
|
||||||
cache.On("Set").Return()
|
cache.On("Set").Return()
|
||||||
env.On("Cache").Return(cache)
|
env.On("Cache").Return(cache)
|
||||||
|
|
||||||
|
|
|
@ -35,14 +35,20 @@ import Config from '@site/src/components/Config.js';
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `apikey` | `string` | Your API key from [Open Weather Map][owm] |
|
| `apikey` | `string` | Your API key from [Open Weather Map][owm] |
|
||||||
| `location` | `string` | The requested location. Formatted as <City,STATE,COUNTRY_CODE>. City name, state code and country code divided by comma. Please, refer to ISO 3166 for the state codes or country codes - defaults to `DE BILT,NL` |
|
| `latitude` | `float64` | The latitude of the requested location. |
|
||||||
| `units` | `string` | Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit) - defaults to `standard` |
|
| `longitude` | `float64` | The longitude of the requested location. |
|
||||||
| `http_timeout` | `int` | The default timeout for http request is 20ms. |
|
| `location` | `string` | The requested location. Formatted as <City,STATE,COUNTRY_CODE>. City name, state code and country code divided by comma. Please, refer to ISO 3166 for the state codes or country codes - defaults to `DE BILT,NL` |
|
||||||
| `cache_timeout` | `int` | The default timeout for request caching is 10m. A value of 0 disables the cache. |
|
| `units` | `string` | Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit) - defaults to `standard` |
|
||||||
| `template` | `string` | A go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the properties below - defaults to `{{.Weather}} ({{.Temperature}}{{.UnitIcon}})` |
|
| `http_timeout` | `int` | The default timeout for http request is 20ms. |
|
||||||
|
| `cache_timeout` | `int` | The default timeout for request caching is 10m. A value of 0 disables the cache. |
|
||||||
|
| `template` | `string` | A go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the properties below - defaults to `{{.Weather}} ({{.Temperature}}{{.UnitIcon}})` |
|
||||||
|
|
||||||
|
### Specifying Location
|
||||||
|
|
||||||
|
The given location can either be specified through the Latitude and Longitude properties or through the Location property. If both Latitude and Longitude are specified and valid then Location will be ignored if it is included. If Latitude or Longitude are not specified or are invalid then Location will be used.
|
||||||
|
|
||||||
## Template ([info][templates])
|
## Template ([info][templates])
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue