feat(segment): open weather map

This commit is contained in:
Nico Glas 2021-08-15 21:11:02 +02:00 committed by GitHub
parent 3f02ad4eb3
commit 4f08d660b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 308 additions and 1 deletions

42
docs/docs/segment-owm.md Normal file
View file

@ -0,0 +1,42 @@
---
id: owm
title: Open Weather Map
sidebar_label: Open Weather Map
---
## What
Shows the current weather of a given location.
:::caution
You **must** request an API key at the [Open Weather Map](https://openweathermap.org/price) website.
The free tier for *Current weather and forecasts collection* is sufficient.
:::
## Sample Configuration
```json
{
"type": "owm",
"style": "powerline",
"powerline_symbol": "\uE0B0",
"foreground": "#ffffff",
"background": "#FF0000",
"properties": {
"apikey": "<YOUR_API_KEY>",
"location": "AMSTERDAM,NL",
"units": "metric"
}
}
```
## Properties
- apikey: `string` - Your apikey from [Open Weather Map](https://openweathermap.org)
- 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`
- units: `string` - Units of measurement.
Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit) - defaults to `standard`

View file

@ -44,6 +44,7 @@ module.exports = {
"nbgv", "nbgv",
"node", "node",
"os", "os",
"owm",
"path", "path",
"python", "python",
"root", "root",

View file

@ -121,6 +121,7 @@ const (
Nbgv SegmentType = "nbgv" Nbgv SegmentType = "nbgv"
// Rust writes the cargo version information if cargo.toml is present // Rust writes the cargo version information if cargo.toml is present
Rust SegmentType = "rust" Rust SegmentType = "rust"
OWM SegmentType = "owm"
) )
func (segment *Segment) string() string { func (segment *Segment) string() string {
@ -229,6 +230,7 @@ func (segment *Segment) background() string {
func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error { func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error {
segment.env = env segment.env = env
functions := map[SegmentType]SegmentWriter{ functions := map[SegmentType]SegmentWriter{
OWM: &owm{},
Session: &session{}, Session: &session{},
Path: &path{}, Path: &path{},
Git: &git{}, Git: &git{},

88
src/segment_owd.go Normal file
View file

@ -0,0 +1,88 @@
package main
import (
"encoding/json"
"fmt"
)
type owm struct {
props *properties
env environmentInfo
temperature float64
weather string
}
const (
APIKEY Property = "apikey"
LOCATION Property = "location"
UNITS Property = "units"
)
type weather struct {
ShortDescription string `json:"main"`
Description string `json:"description"`
TypeID string `json:"icon"`
}
type temperature struct {
Value float64 `json:"temp"`
}
type OWMDataResponse struct {
Data []weather `json:"weather"`
temperature `json:"main"`
}
func (d *owm) enabled() bool {
err := d.setStatus()
return err == nil
}
func (d *owm) string() string {
return fmt.Sprintf("%s (%g\ue33e)", d.weather, d.temperature)
}
func (d *owm) setStatus() error {
apikey := d.props.getString(APIKEY, ".")
location := d.props.getString(LOCATION, "De Bilt,NL")
units := d.props.getString(UNITS, "standard")
url := fmt.Sprintf("http://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s", location, units, apikey)
body, err := d.env.doGet(url)
if err != nil {
return err
}
q := new(OWMDataResponse)
err = json.Unmarshal(body, &q)
if err != nil {
return err
}
d.temperature = q.temperature.Value
icon := ""
switch q.Data[0].TypeID {
case "01d":
icon = "\ufa98"
case "02d":
icon = "\ufa94"
case "03d":
icon = "\ue33d"
case "04d":
icon = "\ue312"
case "09d":
icon = "\ufa95"
case "10d":
icon = "\ue308"
case "11d":
icon = "\ue31d"
case "13d":
icon = "\ue31a"
case "50d":
icon = "\ue313"
}
d.weather = icon
return nil
}
func (d *owm) init(props *properties, env environmentInfo) {
d.props = props
d.env = env
}

139
src/segment_owd_test.go Normal file
View file

@ -0,0 +1,139 @@
package main
import (
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestOWDSegmentSingle(t *testing.T) {
cases := []struct {
Case string
JSONResponse string
ExpectedString string
ExpectedEnabled bool
Error error
}{
{
Case: "Sunny Display",
JSONResponse: `{"weather":[{"icon":"01d"}],"main":{"temp":20}}`,
ExpectedString: "\ufa98 (20\ue33e)",
ExpectedEnabled: true,
},
{
Case: "Error in retrieving data",
JSONResponse: "nonsense",
Error: errors.New("Something went wrong"),
ExpectedEnabled: false,
},
}
for _, tc := range cases {
env := &MockedEnvironment{}
props := &properties{
values: map[Property]interface{}{
APIKEY: "key",
LOCATION: "AMSTERDAM,NL",
UNITS: "metric",
},
}
url := "http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key"
env.On("doGet", url).Return([]byte(tc.JSONResponse), tc.Error)
o := &owm{
props: props,
env: env,
}
enabled := o.enabled()
assert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)
if !enabled {
continue
}
assert.Equal(t, tc.ExpectedString, o.string(), tc.Case)
}
}
func TestOWDSegmentIcons(t *testing.T) {
cases := []struct {
Case string
IconID string
ExpectedIconString string
}{
{
Case: "Sunny Display",
IconID: "01d",
ExpectedIconString: "\ufa98",
},
{
Case: "Light clouds Display",
IconID: "02d",
ExpectedIconString: "\ufa94",
},
{
Case: "Cloudy Display",
IconID: "03d",
ExpectedIconString: "\ue33d",
},
{
Case: "Broken Clouds Display",
IconID: "04d",
ExpectedIconString: "\ue312",
},
{
Case: "Shower Rain Display",
IconID: "09d",
ExpectedIconString: "\ufa95",
},
{
Case: "Rain Display",
IconID: "10d",
ExpectedIconString: "\ue308",
},
{
Case: "Thunderstorm Display",
IconID: "11d",
ExpectedIconString: "\ue31d",
},
{
Case: "Snow Display",
IconID: "13d",
ExpectedIconString: "\ue31a",
},
{
Case: "Fog Display",
IconID: "50d",
ExpectedIconString: "\ue313",
},
}
for _, tc := range cases {
env := &MockedEnvironment{}
props := &properties{
values: map[Property]interface{}{
APIKEY: "key",
LOCATION: "AMSTERDAM,NL",
UNITS: "metric",
},
}
url := "http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key"
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, tc.IconID)
expectedString := fmt.Sprintf("%s (20\ue33e)", tc.ExpectedIconString)
env.On("doGet", url).Return([]byte(response), nil)
o := &owm{
props: props,
env: env,
}
assert.Nil(t, o.setStatus())
assert.Equal(t, expectedString, o.string(), tc.Case)
}
}

View file

@ -1518,6 +1518,41 @@
} }
} }
}, },
{
"if": {
"properties": {
"type": { "const": "owm" }
}
},
"then": {
"title": "Open Weather Map Segment",
"description": "Displays the current weather from the Open Weather Map system",
"properties": {
"properties": {
"properties": {
"apikey": {
"type": "string",
"title": "apikey",
"description": "The apikey used for the api call (Required)",
"default": "."
},
"location": {
"type": "string",
"title": "location",
"description": "Location to use for the api call. 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.",
"default": "De Bilt,NL"
},
"units": {
"type": "string",
"title": "units",
"description": "Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit). Default is standard",
"default": "standard"
}
}
}
}
}
},
{ {
"if": { "if": {
"properties": { "properties": {