all repos — paprika @ profile

go rewrite of taigabot

plugins/weather/weather.go (view raw)

  1package weather
  2
  3import (
  4	_ "embed"
  5	"encoding/json"
  6	"fmt"
  7	"net/http"
  8	"strings"
  9)
 10
 11type WeatherData struct {
 12	Properties struct {
 13		Meta struct {
 14			Units struct {
 15				AirPressureAtSeaLevel string `json:"air_pressure_at_sea_level"`
 16				AirTemperature        string `json:"air_temperature"`
 17				RelativeHumidity      string `json:"relative_humidity"`
 18				WindSpeed             string `json:"wind_speed"`
 19			} `json:"units"`
 20		} `json:"meta"`
 21		Timeseries []struct {
 22			Data struct {
 23				Instant struct {
 24					Details struct {
 25						AirPressureAtSeaLevel float64 `json:"air_pressure_at_sea_level"`
 26						AirTemperature        float64 `json:"air_temperature"`
 27						RelativeHumidity      float64 `json:"relative_humidity"`
 28						WindSpeed             float64 `json:"wind_speed"`
 29					} `json:"details"`
 30				} `json:"instant"`
 31				Next12Hours struct {
 32					Summary struct {
 33						SymbolCode string `json:"symbol_code"`
 34					} `json:"summary"`
 35				} `json:"next_12_hours"`
 36			} `json:"data"`
 37		} `json:"timeseries"`
 38	} `json:"properties"`
 39}
 40
 41func getWeatherData(lonlat [2]float64) (*WeatherData, error) {
 42	url := "https://api.met.no/weatherapi/locationforecast/2.0/compact.json?lat=%f16&lon=%f"
 43	url = fmt.Sprintf(url, lonlat[1], lonlat[0])
 44
 45	client := &http.Client{}
 46	req, _ := http.NewRequest("GET", url, nil)
 47	req.Header.Add("User-Agent", "github.com/icyphox/paprika")
 48
 49	res, err := client.Do(req)
 50	if err != nil {
 51		return nil, err
 52	}
 53
 54	wd := WeatherData{}
 55
 56	json.NewDecoder(res.Body).Decode(&wd)
 57	defer res.Body.Close()
 58
 59	return &wd, nil
 60}
 61
 62func ctof(c float64) float64 {
 63	return c*9/5 + 32
 64}
 65
 66//go:embed data/weather.json
 67var wj []byte
 68
 69func symbolToDesc(s string) string {
 70	m := make(map[string]string)
 71	json.Unmarshal(wj, &m)
 72
 73	// Some symbols have a _, which isn't present in
 74	// the data. So we strip it.
 75	s = strings.Split(s, "_")[0]
 76
 77	return m[s] + ", "
 78}
 79
 80// Looks like Nominatim uses (lon,lat).
 81func GetWeather(lonlat [2]float64, location string) (string, error) {
 82	wd, err := getWeatherData(lonlat)
 83	if err != nil {
 84		return "", err
 85	}
 86
 87	info := strings.Builder{}
 88
 89	// Location.
 90	fmt.Fprintf(&info, "\x02%s\x02: ", location)
 91
 92	// Description of weather.
 93	sym := wd.Properties.Timeseries[0].Data.Next12Hours.Summary.SymbolCode
 94	desc := symbolToDesc(sym)
 95	fmt.Fprintf(&info, "%s", desc)
 96
 97	// Current temperature.
 98	temp := wd.Properties.Timeseries[0].Data.Instant.Details.AirTemperature
 99	var tempFmt string
100	if temp > 28 {
101		tempFmt = "\x0304%0.2f°C\x03 (\x0304%0.2f°F\x03), "
102	} else if temp > 18 {
103		tempFmt = "\x0303%0.2f°C\x03 (\x0303%0.2f°F\x03), "
104	} else {
105		tempFmt = "\x0311%0.2f°C\x03 (\x0311%0.2f°F\x03), "
106	}
107	fmt.Fprintf(
108		&info,
109		"\x02Currently:\x02 "+tempFmt,
110		temp,
111		ctof(temp),
112	)
113
114	// Humidity.
115	hum := wd.Properties.Timeseries[0].Data.Instant.Details.RelativeHumidity
116	humUnit := wd.Properties.Meta.Units.RelativeHumidity
117	fmt.Fprintf(
118		&info,
119		"\x02Humidity:\x02 %0.2f%s, ",
120		hum,
121		humUnit,
122	)
123
124	// Wind speed.
125	ws := wd.Properties.Timeseries[0].Data.Instant.Details.WindSpeed
126	wsUnit := wd.Properties.Meta.Units.WindSpeed
127	fmt.Fprintf(
128		&info,
129		"\x02Wind Speed:\x02 %0.1f %s, ",
130		ws,
131		wsUnit,
132	)
133
134	// Pressure.
135	ps := wd.Properties.Timeseries[0].Data.Instant.Details.AirPressureAtSeaLevel
136	psUnit := wd.Properties.Meta.Units.AirPressureAtSeaLevel
137	fmt.Fprintf(&info,
138		"\x02Pressure:\x02 %0.1f %s",
139		ps,
140		psUnit,
141	)
142
143	return info.String(), nil
144}