1
0
Fork 0
mirror of https://github.com/Luzifer/go-metar.git synced 2024-10-18 05:04:21 +00:00
go-metar/metar.go

129 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package metar
import (
"encoding/xml"
"errors"
"fmt"
"net/http"
"time"
)
const (
apiSource = "https://www.aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=xml&stationString=%s&hoursBeforeNow=2&mostRecent=true"
)
var (
// HTTPClient is used to make requests, you can insert your own
HTTPClient = http.DefaultClient
)
// Result holds all the data from the METAR request
type Result struct {
XMLName xml.Name `xml:"METAR"`
RawText string `xml:"raw_text"` // The raw METAR
StationID string `xml:"station_id"` // Station identifier; Always a four character alphanumeric( A-Z, 0-9)
ObservationTime time.Time `xml:"observation_time"` // Time this METAR was observed
Latitude float64 `xml:"latitude"` // The latitude (in decimal degrees) of the station that reported this METAR
Longitude float64 `xml:"longitude"` // The longitude (in decimal degrees) of the station that reported this METAR
Temperature float64 `xml:"temp_c"` // Air temperature (celsius)
Dewpoint float64 `xml:"dewpoint_c"` // Dewpoint temperature (celsius)
WindDirDegrees int64 `xml:"wind_dir_degrees"` // Direction from which the wind is blowing. 0 degrees=variable wind direction.
WindSpeed int64 `xml:"wind_speed_kt"` // Wind speed; 0 degree wdir and 0 wspd = calm winds (kts)
WindGust int64 `xml:"wind_gust_kt"` // Wind gust
VisibilityStatute float64 `xml:"visibility_statute_mi"` // Horizontal visibility (statute miles)
Altimeter float64 `xml:"altim_in_hg"` // Altimeter (inches of Hg)
SeaLevelPressure float64 `xml:"sea_level_pressure_mb"` // Sea-level pressure (mb)
QualityControlFlags QualityControlFlags `xml:"quality_control_flags"` // Quality control flags provide useful information about the METAR station(s) that provide the data.
WXString string `xml:"wx_string"` // WX string descriptions (https://www.aviationweather.gov/static/adds/docs/metars/wxSymbols_anno2.pdf)
SkyCondition struct {
SkyCover SkyCover `xml:"sky_cover,attr"` // Sky cover, up to four levels of sky cover can be reported ; OVX present when vert_vis_ft is reported
} `xml:"sky_condition"`
FlightCategory FlightCategory `xml:"flight_category"` // Flight category of this METAR
// Fields 19 to 29 currently not implemented
MetarType string `xml:"metar_type"` // METAR or SPECI
Elevation float64 `xml:"elevation_m"` // The elevation of the station that reported this METAR (meters)
}
// QualityControlFlags provide useful information about the METAR station(s) that provide the data.
type QualityControlFlags struct {
XMLName xml.Name `xml:"quality_control_flags"`
NoSignal bool `xml:"no_signal"`
}
// SkyCover defines and explains possible sky coverage situations
type SkyCover string
// Common SkyCover situations
const (
SkyCoverSKC SkyCover = "SKC" // "No cloud/Sky clear" used worldwide but in North America is used to indicate a human generated report
SkyCoverCLR SkyCover = "CLR" // "No clouds below 12,000 ft (3,700 m) (U.S.) or 25,000 ft (7,600 m) (Canada)", used mainly within North America and indicates a station that is at least partly automated
SkyCoverNSC SkyCover = "NSC" // "No (nil) significant cloud", i.e., none below 5,000 ft (1,500 m) and no TCU or CB. Not used in North America.
SkyCoverFEW SkyCover = "FEW" // "Few" = 12 oktas
SkyCoverSCT SkyCover = "SCT" // "Scattered" = 34 oktas
SkyCoverBKN SkyCover = "BKN" // "Broken" = 57 oktas
SkyCoverOVC SkyCover = "OVC" // "Overcast" = 8 oktas, i.e., full cloud coverage
SkyCoverCAVOK SkyCover = "CAVOK" // Ceiling And Visibility OKay, indicating no cloud below 5,000 ft (1,500 m) or the highest minimum sector altitude and no cumulonimbus or towering cumulus at any level, a visibility of 10 km (6 mi) or more and no significant weather change
)
// FlightCategory defines and explains possible flight category situations
type FlightCategory string
// Common FlightCategory situations
const (
FlightCategoryVFR FlightCategory = "VFR" // Visual Flight Rules (Ceiling greater than 3,000 feet AGL and visibility greater than 5 miles)
FlightCategoryMVFR FlightCategory = "MVFR" // Marginal Visual Flight Rules (Ceiling 1,000 to 3,000 feet AGL and/or visibility 3 to 5 miles)
FlightCategoryIFR FlightCategory = "IFR" // Instrument Flight Rules (Ceiling 500 to below 1,000 feet AGL and/or visibility 1 mile to less than 3 miles)
FlightCategoryLIFR FlightCategory = "LIFR" // Low Instrument Flight Rules (Ceiling below 500 feet AGL and/or visibility less than 1 mile)
)
type response struct {
XMLName xml.Name `xml:"response"`
Data struct {
NumResults int `xml:"num_results,attr"`
Results []Result `xml:"METAR"`
} `xml:"data"`
}
// FetchCurrentStationWeather fetches the last result from the specified station if it was reported during last 2 hours
func FetchCurrentStationWeather(station string) (*Result, error) {
req, _ := http.NewRequest("GET", fmt.Sprintf(apiSource, station), nil)
res, err := HTTPClient.Do(req)
if err != nil {
return nil, err
}
r := &response{}
if err = xml.NewDecoder(res.Body).Decode(r); err != nil {
return nil, err
}
if r.Data.NumResults != len(r.Data.Results) {
return nil, errors.New("Got inconsistent number of results")
}
if r.Data.NumResults == 0 {
return nil, errors.New("Did not find any data for your station")
}
return &r.Data.Results[0], nil
}
// InHgTohPa converts "inch of mercury" to "hectopascal"
func InHgTohPa(inHg float64) float64 {
return inHg * 33.8638866667
}
// KtsToMs converts "knots" to "meters per second"
func KtsToMs(kts float64) float64 {
return kts * 0.514444
}
// StatMileToKm converts "statute miles" to "kilometers"
func StatMileToKm(sm float64) float64 {
return sm * 1.60934
}
// MbTohPa converts "millibar" to "hectopascal"
func MbTohPa(mb float64) float64 {
return mb * 0.1
}