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 import ( "encoding/json" "flag" "fmt" "io/ioutil" "log" "net/http" "sort" ) const defid = "310118" var wkey = map[string]string{ "f": "Feels Like Temperature", "h": "Humidity", "p": "Pressure", "t": "Temperature", "v": "Visibility", "wg": "Wind Gust", "ws": "Wind Speed", "pp": "Precipitaton Probability", "uv": "Max UV Index", "wd": "Wind Direction", "wt": "Weather Type", "AQIndex": "Air Quality", } type Response struct { BestFcst struct { Location struct { Days []Day `json:"Day"` } } } type Day struct { DayValues WeatherParam NightValues WeatherParam TimeSteps struct { TimeStep struct { Time string `json:"@time"` WeatherParams []WeatherParam } } } type WeatherParam struct { AQIndex float64 F float64 H float64 P float64 PP float64 UV float64 T float64 V float64 WD string WG float64 WS float64 WT float64 } func main() { var j map[string]interface{} var id string flag.Parse() if flag.NArg() > 0 { id = flag.Arg(0) } else { id = defid } // Use http.Client.Get as http.Get doesn't seem to handle TLS client := &http.Client{Transport: &http.Transport{}} resp, err := client.Get("https://www.metoffice.gov.uk/public/data/PWSCache/BestForecast/Forecast/" + id + ".json?concise=true") if err != nil { log.Fatal(err) } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) err = json.Unmarshal(b, &j) if err != nil { log.Fatal(err) } // TODO: make this cleaner, perhaps by pre-speccing the structs days := j["BestFcst"].(map[string]interface{})["Forecast"].(map[string]interface{})["Location"].(map[string]interface{})["Day"].([]interface{}) for _, d := range days { fmt.Printf("-----------------------------\n") fmt.Printf("Date: %v\n", d.(map[string]interface{})["@date"]) fmt.Printf("\nDay weather:\n") prettyWeather(d.(map[string]interface{})["DayValues"].(map[string]interface{})["WeatherParameters"].(map[string]interface{})) fmt.Printf("\nNight weather:\n") prettyWeather(d.(map[string]interface{})["NightValues"].(map[string]interface{})["WeatherParameters"].(map[string]interface{})) fmt.Printf("\nTime steps:\n") timesteps := d.(map[string]interface{})["TimeSteps"].(map[string]interface{})["TimeStep"].([]interface{}) for _, t := range timesteps { fmt.Printf("\nTime: %s\n", t.(map[string]interface{})["@time"]) prettyWeather(t.(map[string]interface{})["WeatherParameters"].(map[string]interface{})) } } } func prettyWeather(w map[string]interface{}) { // TODO: choose what to show, and in what order, to have a compact output var keys []string for k, _ := range wkey { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { t, ok := w[k] if ok { fmt.Printf("%s: %v\n", wkey[k], t) } } }