Added SnowHeight and corrected comments
This commit is contained in:
parent
7bdf2de388
commit
8cb9754f69
|
@ -50,6 +50,8 @@ type APICurrentWeatherData struct {
|
|||
PressureQFE *APIFloat `json:"pressure,omitempty"`
|
||||
// SnowAmount represents the the amount of snow in kg/m3
|
||||
SnowAmount *APIFloat `json:"snowAmount,omitempty"`
|
||||
// SnowHeight represents the the height of snow in m
|
||||
SnowHeight *APIFloat `json:"snowHeight,omitempty"`
|
||||
// Temperature represents the temperature in °C
|
||||
Temperature *APIFloat `json:"temp,omitempty"`
|
||||
// WindDirection represents the direction from which the wind
|
||||
|
@ -249,7 +251,7 @@ func (cw CurrentWeather) PressureQFE() Pressure {
|
|||
return v
|
||||
}
|
||||
|
||||
// SnowAmount returns the temperature data point as Density.
|
||||
// SnowAmount returns the amount of snow data point as Density.
|
||||
// If the data point is not available in the CurrentWeather it will return
|
||||
// Density in which the "not available" field will be true.
|
||||
func (cw CurrentWeather) SnowAmount() Density {
|
||||
|
@ -268,6 +270,25 @@ func (cw CurrentWeather) SnowAmount() Density {
|
|||
return v
|
||||
}
|
||||
|
||||
// SnowHeight returns the snow height data point as Height.
|
||||
// If the data point is not available in the CurrentWeather it will return
|
||||
// Height in which the "not available" field will be true.
|
||||
func (cw CurrentWeather) SnowHeight() Height {
|
||||
if cw.Data.SnowHeight == nil {
|
||||
return Height{na: true}
|
||||
}
|
||||
v := Height{
|
||||
dt: cw.Data.SnowHeight.DateTime,
|
||||
n: FieldSnowHeight,
|
||||
s: SourceUnknown,
|
||||
fv: cw.Data.SnowHeight.Value,
|
||||
}
|
||||
if cw.Data.SnowHeight.Source != nil {
|
||||
v.s = StringToSource(*cw.Data.SnowHeight.Source)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// Temperature returns the temperature data point as Temperature.
|
||||
// If the data point is not available in the CurrentWeather it will return
|
||||
// Temperature in which the "not available" field will be true.
|
||||
|
|
|
@ -626,6 +626,103 @@ func TestClient_CurrentWeatherByLocation_SnowAmount(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestClient_CurrentWeatherByLocation_SnowHeight(t *testing.T) {
|
||||
tt := []struct {
|
||||
// Location name
|
||||
loc string
|
||||
// CurWeather height
|
||||
h *Height
|
||||
}{
|
||||
{"Ehrenfeld, Germany", &Height{
|
||||
dt: time.Date(2023, 5, 23, 6, 0, 0, 0, time.UTC),
|
||||
s: SourceAnalysis,
|
||||
fv: 1.23,
|
||||
}},
|
||||
{"Berlin, Germany", &Height{
|
||||
dt: time.Date(2023, 5, 23, 6, 0, 0, 0, time.UTC),
|
||||
s: SourceAnalysis,
|
||||
fv: 0.003,
|
||||
}},
|
||||
{"Neermoor, Germany", nil},
|
||||
}
|
||||
c := New(withMockAPI())
|
||||
if c == nil {
|
||||
t.Errorf("failed to create new Client, got nil")
|
||||
return
|
||||
}
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.loc, func(t *testing.T) {
|
||||
cw, err := c.CurrentWeatherByLocation(tc.loc)
|
||||
if err != nil {
|
||||
t.Errorf("CurrentWeatherByLocation failed: %s", err)
|
||||
return
|
||||
}
|
||||
if tc.h != nil && tc.h.String() != cw.SnowHeight().String() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"string: %s, got: %s", tc.h.String(), cw.SnowHeight())
|
||||
}
|
||||
if tc.h != nil && tc.h.Value() != cw.SnowHeight().Value() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"float: %f, got: %f", tc.h.Value(), cw.SnowHeight().Value())
|
||||
}
|
||||
if tc.h != nil && tc.h.MeterString() != cw.SnowHeight().MeterString() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"string: %s, got: %s", tc.h.MeterString(), cw.SnowHeight().MeterString())
|
||||
}
|
||||
if tc.h != nil && tc.h.Meter() != cw.SnowHeight().Meter() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"float: %f, got: %f", tc.h.Meter(), cw.SnowHeight().Meter())
|
||||
}
|
||||
if tc.h != nil && tc.h.CentiMeterString() != cw.SnowHeight().CentiMeterString() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"string: %s, got: %s", tc.h.CentiMeterString(), cw.SnowHeight().CentiMeterString())
|
||||
}
|
||||
if tc.h != nil && tc.h.CentiMeter() != cw.SnowHeight().CentiMeter() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"float: %f, got: %f", tc.h.CentiMeter(), cw.SnowHeight().CentiMeter())
|
||||
}
|
||||
if tc.h != nil && tc.h.MilliMeterString() != cw.SnowHeight().MilliMeterString() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"string: %s, got: %s", tc.h.MilliMeterString(), cw.SnowHeight().MilliMeterString())
|
||||
}
|
||||
if tc.h != nil && tc.h.MilliMeter() != cw.SnowHeight().MilliMeter() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"float: %f, got: %f", tc.h.MilliMeter(), cw.SnowHeight().MilliMeter())
|
||||
}
|
||||
if tc.h != nil && cw.SnowHeight().Source() != tc.h.s {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected source: %s, but got: %s",
|
||||
tc.h.s, cw.SnowHeight().Source())
|
||||
}
|
||||
if tc.h != nil && tc.h.dt.Unix() != cw.SnowHeight().DateTime().Unix() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected datetime: %s, got: %s",
|
||||
tc.h.dt.Format(time.RFC3339), cw.SnowHeight().DateTime().Format(time.RFC3339))
|
||||
}
|
||||
if tc.h == nil {
|
||||
if cw.SnowHeight().IsAvailable() {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"to have no data, but got: %s", cw.SnowHeight())
|
||||
}
|
||||
if !math.IsNaN(cw.SnowHeight().Value()) {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"to return NaN, but got: %s", cw.SnowHeight().String())
|
||||
}
|
||||
if !math.IsNaN(cw.SnowHeight().Meter()) {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"to return NaN, but got: %f", cw.SnowHeight().Meter())
|
||||
}
|
||||
if !math.IsNaN(cw.SnowHeight().CentiMeter()) {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"to return NaN, but got: %f", cw.SnowHeight().CentiMeter())
|
||||
}
|
||||
if !math.IsNaN(cw.SnowHeight().MilliMeter()) {
|
||||
t.Errorf("CurrentWeatherByLocation failed, expected snow height "+
|
||||
"to return NaN, but got: %f", cw.SnowHeight().MilliMeter())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_CurrentWeatherByLocation_Temperature(t *testing.T) {
|
||||
tt := []struct {
|
||||
// Location name
|
||||
|
|
|
@ -46,6 +46,8 @@ const (
|
|||
FieldPressureQFE
|
||||
// FieldSnowAmount represents the SnowAmount data point
|
||||
FieldSnowAmount
|
||||
// FieldSnowHeight represents the SnowHeight data point
|
||||
FieldSnowHeight
|
||||
// FieldSunrise represents the Sunrise data point
|
||||
FieldSunrise
|
||||
// FieldSunset represents the Sunset data point
|
||||
|
|
|
@ -38,7 +38,7 @@ func (d Density) Source() Source {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Density
|
||||
// If the Density is not available in the Observation
|
||||
// If the Density is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (d Density) Value() float64 {
|
||||
if d.na {
|
||||
|
|
|
@ -62,7 +62,7 @@ func (d Direction) DateTime() time.Time {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Direction in degrees
|
||||
// If the Direction is not available in the Observation
|
||||
// If the Direction is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (d Direction) Value() float64 {
|
||||
if d.na {
|
||||
|
|
86
height.go
Normal file
86
height.go
Normal file
|
@ -0,0 +1,86 @@
|
|||
// SPDX-FileCopyrightText: 2023 Winni Neessen <wn@neessen.dev>
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package meteologix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Height is a type wrapper of an WeatherData for holding height
|
||||
// values in WeatherData (based on meters a default unit)
|
||||
type Height WeatherData
|
||||
|
||||
// IsAvailable returns true if an Height value was
|
||||
// available at time of query
|
||||
func (h Height) IsAvailable() bool {
|
||||
return !h.na
|
||||
}
|
||||
|
||||
// DateTime returns true if an Height value was
|
||||
// available at time of query
|
||||
func (h Height) DateTime() time.Time {
|
||||
return h.dt
|
||||
}
|
||||
|
||||
// String satisfies the fmt.Stringer interface for the Height type
|
||||
func (h Height) String() string {
|
||||
return fmt.Sprintf("%.3fm", h.fv)
|
||||
}
|
||||
|
||||
// Source returns the Source of Height
|
||||
// If the Source is not available it will return SourceUnknown
|
||||
func (h Height) Source() Source {
|
||||
return h.s
|
||||
}
|
||||
|
||||
// Value returns the float64 value of an Height
|
||||
// If the Height is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (h Height) Value() float64 {
|
||||
if h.na {
|
||||
return math.NaN()
|
||||
}
|
||||
return h.fv
|
||||
}
|
||||
|
||||
// Meter returns the Height type value as float64 in meters.
|
||||
// This is an alias for the Value() method
|
||||
func (h Height) Meter() float64 {
|
||||
return h.Value()
|
||||
}
|
||||
|
||||
// MeterString returns the Height type as formatted string in meters
|
||||
// This is an alias for the String() method
|
||||
func (h Height) MeterString() string {
|
||||
return h.String()
|
||||
}
|
||||
|
||||
// CentiMeter returns the Height type value as float64 in centimeters.
|
||||
func (h Height) CentiMeter() float64 {
|
||||
if h.na {
|
||||
return math.NaN()
|
||||
}
|
||||
return h.fv / 100
|
||||
}
|
||||
|
||||
// CentiMeterString returns the Height type as formatted string in centimeters
|
||||
func (h Height) CentiMeterString() string {
|
||||
return fmt.Sprintf("%.3fcm", h.CentiMeter())
|
||||
}
|
||||
|
||||
// MilliMeter returns the Height type value as float64 in milliimeters.
|
||||
func (h Height) MilliMeter() float64 {
|
||||
if h.na {
|
||||
return math.NaN()
|
||||
}
|
||||
return h.fv / 1000
|
||||
}
|
||||
|
||||
// MilliMeterString returns the Height type as formatted string in millimeters
|
||||
func (h Height) MilliMeterString() string {
|
||||
return fmt.Sprintf("%.3fmm", h.MilliMeter())
|
||||
}
|
|
@ -38,7 +38,7 @@ func (h Humidity) Source() Source {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Humidity
|
||||
// If the Humidity is not available in the Observation
|
||||
// If the Humidity is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (h Humidity) Value() float64 {
|
||||
if h.na {
|
||||
|
|
|
@ -38,7 +38,7 @@ func (p Precipitation) Source() Source {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Precipitation
|
||||
// If the Precipitation is not available in the Observation
|
||||
// If the Precipitation is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (p Precipitation) Value() float64 {
|
||||
if p.na {
|
||||
|
|
|
@ -38,7 +38,7 @@ func (p Pressure) Source() Source {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Pressure
|
||||
// If the Pressure is not available in the Observation
|
||||
// If the Pressure is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (p Pressure) Value() float64 {
|
||||
if p.na {
|
||||
|
|
|
@ -27,7 +27,7 @@ func (r Radiation) DateTime() time.Time {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Radiation
|
||||
// If the Radiation is not available in the Observation
|
||||
// If the Radiation is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (r Radiation) Value() float64 {
|
||||
if r.na {
|
||||
|
|
2
speed.go
2
speed.go
|
@ -37,7 +37,7 @@ func (s Speed) DateTime() time.Time {
|
|||
|
||||
// Value returns the float64 value of an Speed in meters
|
||||
// per second.
|
||||
// If the Speed is not available in the Observation
|
||||
// If the Speed is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (s Speed) Value() float64 {
|
||||
if s.na {
|
||||
|
|
28
station.go
28
station.go
|
@ -18,12 +18,12 @@ import (
|
|||
const DefaultRadius int = 10
|
||||
|
||||
const (
|
||||
// PrecisionHigh is a high precision weather station
|
||||
PrecisionHigh Precision = iota
|
||||
// PrecisionMedium is a medium precision weather station
|
||||
PrecisionMedium
|
||||
// PrecisionLow is a low precision weather station
|
||||
PrecisionLow
|
||||
// PrecisionSuperHigh represents data of < ~4km resolution
|
||||
PrecisionSuperHigh Precision = iota
|
||||
// PrecisionHigh represents data of >= ~4km but < ~10km resolution
|
||||
PrecisionHigh
|
||||
// PrecisionStandard represents data of >= ~10km resolution
|
||||
PrecisionStandard
|
||||
// PrecisionUnknown is weather station of unknown precision
|
||||
PrecisionUnknown
|
||||
)
|
||||
|
@ -157,12 +157,12 @@ func (p *Precision) UnmarshalJSON(s []byte) error {
|
|||
v := string(s)
|
||||
v = strings.ReplaceAll(v, `"`, ``)
|
||||
switch strings.ToLower(v) {
|
||||
case "super_high":
|
||||
*p = PrecisionSuperHigh
|
||||
case "high":
|
||||
*p = PrecisionHigh
|
||||
case "medium":
|
||||
*p = PrecisionMedium
|
||||
case "low":
|
||||
*p = PrecisionLow
|
||||
case "standard":
|
||||
*p = PrecisionStandard
|
||||
default:
|
||||
*p = PrecisionUnknown
|
||||
}
|
||||
|
@ -172,12 +172,12 @@ func (p *Precision) UnmarshalJSON(s []byte) error {
|
|||
// String satisfies the fmt.Stringer interface for the Precision type
|
||||
func (p *Precision) String() string {
|
||||
switch *p {
|
||||
case PrecisionSuperHigh:
|
||||
return "SUPER_HIGH"
|
||||
case PrecisionHigh:
|
||||
return "HIGH"
|
||||
case PrecisionMedium:
|
||||
return "MEDIUM"
|
||||
case PrecisionLow:
|
||||
return "LOW"
|
||||
case PrecisionStandard:
|
||||
return "STANDARD"
|
||||
case PrecisionUnknown:
|
||||
return "UNKNOWN"
|
||||
default:
|
||||
|
|
|
@ -164,16 +164,16 @@ func TestPrecision_UnmarshalJSON(t *testing.T) {
|
|||
// Should fail
|
||||
sf bool
|
||||
}{
|
||||
{
|
||||
"Super high precision", []byte(`{"precision":"SUPER_HIGH"}`), PrecisionSuperHigh,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"High precision", []byte(`{"precision":"HIGH"}`), PrecisionHigh,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Medium precision", []byte(`{"precision":"MEDIUM"}`), PrecisionMedium,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Low precision", []byte(`{"precision":"LOW"}`), PrecisionLow,
|
||||
"Standard precision", []byte(`{"precision":"STANDARD"}`), PrecisionStandard,
|
||||
false,
|
||||
},
|
||||
{
|
||||
|
@ -209,9 +209,9 @@ func TestPrecision_String(t *testing.T) {
|
|||
// Expected string
|
||||
es string
|
||||
}{
|
||||
{"Super high precision", PrecisionSuperHigh, "SUPER_HIGH"},
|
||||
{"High precision", PrecisionHigh, "HIGH"},
|
||||
{"Medium precision", PrecisionMedium, "MEDIUM"},
|
||||
{"Low precision", PrecisionLow, "LOW"},
|
||||
{"Standard precision", PrecisionStandard, "STANDARD"},
|
||||
{"Unknown precision", PrecisionUnknown, "UNKNOWN"},
|
||||
{"Undefined precision", 999, "UNKNOWN"},
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func (t Temperature) DateTime() time.Time {
|
|||
}
|
||||
|
||||
// Value returns the float64 value of an Temperature
|
||||
// If the Temperature is not available in the Observation
|
||||
// If the Temperature is not available in the WeatherData
|
||||
// Vaule will return math.NaN instead.
|
||||
func (t Temperature) Value() float64 {
|
||||
if t.na {
|
||||
|
|
Loading…
Reference in a new issue