summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--weather.go176
1 files changed, 145 insertions, 31 deletions
diff --git a/weather.go b/weather.go
index 4eb5c13..0f46391 100644
--- a/weather.go
+++ b/weather.go
@@ -1,9 +1,11 @@
package main
// TODO: allow free-text lookups of place names, rather than ids
-// TODO: decode weather type number
-// TODO: split out met office specific stuff to separate module
-// TODO: add other weather providers
+// TODO: convert metoffice windspeed to mph
+// TODO: split output into days
+// TODO: add -n flag to only output a certain number of days
+// TODO: convert weather type number into a human-friendly string
+// TODO: human friendly dates
import (
"encoding/json"
@@ -14,9 +16,50 @@ import (
"net/http"
)
-const defid = "310118"
+const metdefid = "310118"
+const bbcdefid = "2640729"
-type Response struct {
+const meturl = "https://www.metoffice.gov.uk/public/data/PWSCache/BestForecast/Forecast/%s.json?concise=true"
+const bbcurl = "https://weather-broker-cdn.api.bbci.co.uk/en/forecast/aggregated/%s"
+
+// BBC structures
+type BBCResponse struct {
+ Forecasts []struct {
+ Detailed struct {
+ Reports []Report
+ }
+ }
+}
+
+type Report struct {
+ EnhancedWeatherDescription string
+ ExtendedWeatherType int
+ FeelsLikeTemperatureC int
+ FeelsLikeTemperatureF int
+ GustSpeedKph int
+ GustSpeedMph int
+ Humidity int
+ LocalDate string
+ PrecipitationProbabilityInPercent int
+ PrecipitationProbabilityText string
+ Pressure int
+ TemperatureC int
+ TemperatureF int
+ Timeslot string
+ TimeslotLength int
+ Visibility string
+ WeatherType int
+ WeatherTypeText string
+ WindDescription string
+ WindDirection string
+ WindDirectionAbbreviation string
+ WindDirectionFull string
+ WindSpeedKph int
+ WindSpeedMph int
+}
+
+// Met Office structures
+type MetResponse struct {
BestFcst struct {
Forecast struct {
Location struct {
@@ -57,23 +100,106 @@ type WeatherParams struct {
WT int // Weather Type
}
+// Our prefered struct
+type Weather struct {
+ date string
+ time string
+ temperature float64
+ precipitation int
+ weathertype int
+ windspeed float64
+}
+
var (
+ bbc = flag.Bool("b", false, "use bbc as data source")
numdays = flag.Int("n", 2, "number of days to show")
verbose = flag.Bool("v", false, "verbose: show all weather details")
)
+func processBBC(b []byte) []Weather {
+ var r BBCResponse
+ var weather []Weather
+ var w Weather
+ err := json.Unmarshal(b, &r)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, f := range r.Forecasts {
+ for _, report := range f.Detailed.Reports {
+ w.date = report.LocalDate
+ w.time = report.Timeslot
+ w.temperature = float64(report.TemperatureC)
+ w.precipitation = report.PrecipitationProbabilityInPercent
+ w.weathertype = report.WeatherType
+ w.windspeed = float64(report.WindSpeedMph)
+ weather = append(weather, w)
+ }
+ }
+ return weather
+}
+
+func processMet(b []byte) []Weather {
+ var r MetResponse
+ var weather []Weather
+ var w Weather
+ err := json.Unmarshal(b, &r)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, d := range r.BestFcst.Forecast.Location.Days {
+ w.date = d.Date
+ w.time = "Day "
+ w.temperature = d.DayValues.WeatherParameters.T
+ w.precipitation = d.DayValues.WeatherParameters.PP
+ w.weathertype = d.DayValues.WeatherParameters.WT
+ w.windspeed = d.DayValues.WeatherParameters.WS
+ weather = append(weather, w)
+
+ w.date = d.Date
+ w.time = "Night "
+ w.temperature = d.DayValues.WeatherParameters.T
+ w.precipitation = d.DayValues.WeatherParameters.PP
+ w.weathertype = d.DayValues.WeatherParameters.WT
+ w.windspeed = d.DayValues.WeatherParameters.WS
+ weather = append(weather, w)
+
+ for _, t := range d.TimeSteps.TimeStep {
+ w.date = d.Date
+ w.time = t.Time
+ w.temperature = t.WeatherParameters.T
+ w.precipitation = t.WeatherParameters.PP
+ w.weathertype = t.WeatherParameters.WT
+ w.windspeed = t.WeatherParameters.WS
+ weather = append(weather, w)
+ }
+ }
+ return weather
+}
+
func main() {
- var r Response
+ var err error
var id string
+ var resp *http.Response
+ var weather []Weather
flag.Parse()
if flag.NArg() > 0 {
id = flag.Arg(0)
} else {
- id = defid
+ if *bbc {
+ id = bbcdefid
+ } else {
+ id = metdefid
+ }
}
- resp, err := http.Get("https://www.metoffice.gov.uk/public/data/PWSCache/BestForecast/Forecast/" + id + ".json?concise=true")
+ if *bbc {
+ resp, err = http.Get(fmt.Sprintf(bbcurl, id))
+ } else {
+ resp, err = http.Get(fmt.Sprintf(meturl, id))
+ }
if err != nil {
log.Fatal(err)
}
@@ -82,31 +208,19 @@ func main() {
log.Fatalf("HTTP status code: %d\n", resp.StatusCode)
}
b, err := ioutil.ReadAll(resp.Body)
- err = json.Unmarshal(b, &r)
- if err != nil {
- log.Fatal(err)
- }
-
- for i, d := range r.BestFcst.Forecast.Location.Days {
- if *numdays > 0 && i >= *numdays {
- break
- }
- if i > 0 {
- fmt.Printf("---------------------------------------------------------\n")
- }
- fmt.Printf("%s\n", d.Date)
- prettyWeather(" Day", d.DayValues.WeatherParameters)
- prettyWeather(" Night", d.NightValues.WeatherParameters)
- for _, t := range d.TimeSteps.TimeStep {
- prettyWeather(t.Time, t.WeatherParameters)
- }
+ if *bbc {
+ weather = processBBC(b)
+ } else {
+ weather = processMet(b)
}
-}
-func prettyWeather(t string, w WeatherParams) {
- fmt.Printf("%s Type: %2d, Temp: %4.1f°C, Rain: %2d%%, Wind: %2.1fm/s\n", t, w.WT, w.T, w.PP, w.WS)
- if *verbose {
- fmt.Printf(" %+v\n", w)
+ for _, w := range weather {
+ fmt.Printf("%s %s ", w.date, w.time)
+ fmt.Printf("Type: %2d, Temp: %4.1f°C, ", w.weathertype, w.temperature)
+ fmt.Printf("Rain: %2d%%, Wind: %4.1fmph\n", w.precipitation, w.windspeed)
+ if *verbose {
+ fmt.Printf(" %+v\n", w)
+ }
}
}