migrating to go
This commit is contained in:
parent
d27117b8bc
commit
7d14f3a9df
10
go.mod
Normal file
10
go.mod
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module weather
|
||||||
|
|
||||||
|
go 1.22.1
|
||||||
|
|
||||||
|
require github.com/tidwall/gjson v1.17.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
|
)
|
6
go.sum
Normal file
6
go.sum
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
|
||||||
|
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
187
main.go
Normal file
187
main.go
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
// free api for reverse geocoding based on IP
|
||||||
|
const revGeoURL = "http://ip-api.com/json/"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
w := NewWeather()
|
||||||
|
|
||||||
|
if err := w.getLatest(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Weather struct {
|
||||||
|
Temperature float64
|
||||||
|
Humidity float64
|
||||||
|
Conditions string
|
||||||
|
Icon string
|
||||||
|
*Location
|
||||||
|
Static bool //
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWeather() *Weather {
|
||||||
|
l := NewLocation()
|
||||||
|
// try to set location
|
||||||
|
if err := l.getCoords(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := l.getStation(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Weather{
|
||||||
|
Location: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Weather) getLatest() error {
|
||||||
|
url := fmt.Sprintf("https://api.weather.gov/stations/%s/observations/latest", w.Location.Station)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if res.StatusCode > 299 {
|
||||||
|
errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
|
||||||
|
return errors.New(errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
temp := gjson.Get(string(body), "properties.temperature.value")
|
||||||
|
humidity := gjson.Get(string(body), "properties.relativeHumidity.value")
|
||||||
|
cond := gjson.Get(string(body), "properties.textDescription")
|
||||||
|
|
||||||
|
// convert to Farenheit
|
||||||
|
w.Temperature = temp.Float()*(9.0/5) + 32
|
||||||
|
w.Humidity = humidity.Float()
|
||||||
|
w.Conditions = cond.String()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Weather) String() string {
|
||||||
|
return fmt.Sprintf("%s %.1f deg %.1f%% RH in %s, %s", w.Conditions, w.Temperature, w.Humidity, w.Location.City, w.Location.State)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Location struct {
|
||||||
|
Lat float32 `json:"lat"`
|
||||||
|
Lon float32 `json:"lon"`
|
||||||
|
City string `json:"city"`
|
||||||
|
State string `json:"region"`
|
||||||
|
Zipcode string `json:"zip"`
|
||||||
|
Found bool
|
||||||
|
// NWS specific location data
|
||||||
|
Station string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLocation() *Location {
|
||||||
|
return &Location{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Location) getCoords() error {
|
||||||
|
|
||||||
|
res, err := http.Get(revGeoURL)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if res.StatusCode > 299 {
|
||||||
|
errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
|
||||||
|
return errors.New(errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshall response into struct
|
||||||
|
if err := json.Unmarshal(body, l); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Found = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Location) getStation() error {
|
||||||
|
// generate url based on coords
|
||||||
|
url := fmt.Sprintf("https://api.weather.gov/points/%f,%f", l.Lat, l.Lon)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if res.StatusCode > 299 {
|
||||||
|
errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
|
||||||
|
return errors.New(errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// send another request to station URL to find closest
|
||||||
|
stationURL := gjson.Get(string(body), "properties.observationStations")
|
||||||
|
|
||||||
|
res, err = http.Get(stationURL.String())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err = io.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
if res.StatusCode > 299 {
|
||||||
|
errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
|
||||||
|
return errors.New(errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
station := gjson.Get(string(body), "features.0.properties.stationIdentifier")
|
||||||
|
|
||||||
|
if station.String() == "" {
|
||||||
|
return errors.New("Station not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
l.Station = station.String()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// for debugging
|
||||||
|
func (l *Location) String() string {
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s, %s %s (%f, %f) station: %s", l.City, l.State, l.Zipcode, l.Lat, l.Lon, l.Station)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user