Add `.gitignore` Update `go.mod` Add `go.sum` Add `drawing.go` Add `JetBrainsMono-Bold.ttf` Add `JetBrainsMono-Italic.ttf` Add `JetBrainsMono-Regular.ttf` Add `weathericons-regular-webfont.ttf` Add `imagegen.go` Add `kindle-dashboard.test.png` Add `rttclient.go` Add `wxclient.go` Add `rootpasswordtool.txt`
137 lines
3.6 KiB
Go
137 lines
3.6 KiB
Go
package imagegen
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/carlmjohnson/requests"
|
|
"strconv"
|
|
"time"
|
|
"unicode"
|
|
)
|
|
|
|
type rawWxResp struct {
|
|
SiteRep struct {
|
|
DV struct {
|
|
DataDate time.Time `json:"dataDate"`
|
|
Type string `json:"type"`
|
|
Location struct {
|
|
ID string `json:"i"`
|
|
Lat string `json:"lat"`
|
|
Lon string `json:"lon"`
|
|
Name string `json:"name"`
|
|
Country string `json:"country"`
|
|
Continent string `json:"continent"`
|
|
Elevation string `json:"elevation"`
|
|
Period []struct {
|
|
Type string `json:"type"`
|
|
Value string `json:"value"`
|
|
Rep []struct {
|
|
WindDirection string `json:"D"`
|
|
FeelsLikeTemperature string `json:"F"`
|
|
WindGust string `json:"G"`
|
|
RelativeHumidityPercentage string `json:"H"`
|
|
PrecipitationProbability string `json:"Pp"`
|
|
WindSpeed string `json:"S"`
|
|
Temperature string `json:"T"`
|
|
Visibility string `json:"V"`
|
|
WeatherType string `json:"W"`
|
|
MaxUVIndex string `json:"U"`
|
|
MinutesPastMidnight string `json:"$"`
|
|
} `json:"Rep"`
|
|
} `json:"Period"`
|
|
} `json:"Location"`
|
|
} `json:"DV"`
|
|
} `json:"SiteRep"`
|
|
}
|
|
|
|
type weatherEntry struct {
|
|
Time int
|
|
Type int
|
|
Temperature int
|
|
PrecipitationChance int
|
|
WindSpeed int
|
|
}
|
|
|
|
func getWeatherInLocation(apiKey string, location string) (string, []*weatherEntry, error) {
|
|
resp := new(rawWxResp)
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
|
|
err := requests.
|
|
URL("http://datapoint.metoffice.gov.uk").
|
|
Pathf("/public/data/val/wxfcs/all/json/%s", location).
|
|
Params(map[string][]string{
|
|
"key": {apiKey},
|
|
"res": {"3hourly"},
|
|
}).
|
|
ToJSON(&resp).
|
|
Fetch(ctx)
|
|
cancel()
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("get weather: %w", err)
|
|
}
|
|
|
|
// get 4
|
|
|
|
var res []*weatherEntry
|
|
|
|
dayLoop:
|
|
for _, dayWx := range resp.SiteRep.DV.Location.Period {
|
|
day, err := time.Parse("2006-01-02Z", dayWx.Value)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("parse date: %w", err)
|
|
}
|
|
|
|
for _, wx := range dayWx.Rep {
|
|
if len(res) >= 4 {
|
|
break dayLoop
|
|
}
|
|
|
|
minsPastMidnight, err := strconv.Atoi(wx.MinutesPastMidnight)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("parse weather: %w", err)
|
|
}
|
|
thisTime := day.Add(time.Minute * time.Duration(minsPastMidnight))
|
|
if resp.SiteRep.DV.DataDate.Equal(thisTime) || resp.SiteRep.DV.DataDate.Before(thisTime.Add(time.Hour*3)) {
|
|
// if this is applicable
|
|
wxE := new(weatherEntry)
|
|
wxE.Time = minsPastMidnight / 60
|
|
wxE.Type, err = strconv.Atoi(wx.WeatherType)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("parse weather: %w", err)
|
|
}
|
|
{
|
|
temp, err := strconv.ParseFloat(wx.Temperature, 32)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("parse weather: %w", err)
|
|
}
|
|
wxE.Temperature = int(temp)
|
|
}
|
|
{
|
|
precProb, err := strconv.ParseFloat(wx.PrecipitationProbability, 32)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("parse weather: %w", err)
|
|
}
|
|
wxE.PrecipitationChance = int(precProb)
|
|
}
|
|
{
|
|
windSpeed, err := strconv.ParseFloat(wx.WindSpeed, 32)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("parse weather: %w", err)
|
|
}
|
|
wxE.WindSpeed = int(windSpeed)
|
|
}
|
|
res = append(res, wxE)
|
|
}
|
|
}
|
|
}
|
|
|
|
loc := []rune(resp.SiteRep.DV.Location.Name)
|
|
for i, x := range loc {
|
|
if i == 0 || loc[i-1] == ' ' {
|
|
loc[i] = unicode.ToUpper(x)
|
|
} else {
|
|
loc[i] = unicode.ToLower(x)
|
|
}
|
|
}
|
|
|
|
return string(loc), res, nil
|
|
}
|