refactored weather
This commit is contained in:
parent
fb6acf48f8
commit
546f80cfce
18
Makefile
Normal file
18
Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# weather Makefile
|
||||||
|
|
||||||
|
GOCMD=go
|
||||||
|
GOBUILDCMD=${GOCMD} build
|
||||||
|
GOOPTIONS=-mod=vendor -ldflags="-s -w"
|
||||||
|
|
||||||
|
RMCMD=rm
|
||||||
|
BINNAME=weather
|
||||||
|
|
||||||
|
SRCFILES=cmd/weather/*.go
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
build:
|
||||||
|
${GOBUILDCMD} ${GOOPTIONS} ${SRCFILES}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
${RMCMD} -f ${BINNAME}
|
@ -9,7 +9,7 @@ weather is a small program that fetch weather informations, and store them to in
|
|||||||
### Build
|
### Build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build -mod=vendor
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
### Sample config in weather.ini
|
### Sample config in weather.ini
|
||||||
@ -38,7 +38,7 @@ measurements=temp,humidity,pressure
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
```text
|
```text
|
||||||
Copyright (c) 2019, PaulBSD
|
Copyright (c) 2020, PaulBSD
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
@ -64,4 +64,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
The views and conclusions contained in the software and documentation are those
|
The views and conclusions contained in the software and documentation are those
|
||||||
of the authors and should not be interpreted as representing official policies,
|
of the authors and should not be interpreted as representing official policies,
|
||||||
either expressed or implied, of the fuelprices project.
|
either expressed or implied, of the fuelprices project.
|
||||||
```
|
```
|
||||||
|
135
functions.go
135
functions.go
@ -1,135 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
client "github.com/influxdata/influxdb1-client/v2"
|
|
||||||
"gopkg.in/ini.v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetConfig fetch config from ini file
|
|
||||||
func GetConfig(weatherconfig *WeatherConfig, configfile string) error {
|
|
||||||
flag.Usage = Usage
|
|
||||||
|
|
||||||
config, err := ini.Load(configfile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var wc WeatherConfig
|
|
||||||
|
|
||||||
weatherSection := config.Section("weather")
|
|
||||||
|
|
||||||
wc.WeatherAppID = weatherSection.Key("appid").MustString("appid")
|
|
||||||
wc.WeatherCities = weatherSection.Key("cities").Strings(",")
|
|
||||||
if len(wc.WeatherCities) < 1 {
|
|
||||||
return fmt.Errorf("No cities provided in config")
|
|
||||||
}
|
|
||||||
wc.WeatherMeasurements = weatherSection.Key("measurements").Strings(",")
|
|
||||||
if len(wc.WeatherMeasurements) < 1 {
|
|
||||||
return fmt.Errorf("No measurements provided in config")
|
|
||||||
}
|
|
||||||
|
|
||||||
influxdbSection := config.Section("influxdb")
|
|
||||||
wc.InfluxURL = influxdbSection.Key("url").MustString("http://localhost:8086")
|
|
||||||
wc.InfluxUser = influxdbSection.Key("username").MustString("username")
|
|
||||||
wc.InfluxPass = influxdbSection.Key("password").MustString("password")
|
|
||||||
wc.InfluxDB = influxdbSection.Key("database").MustString("me")
|
|
||||||
|
|
||||||
*weatherconfig = wc
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchData fetch data from api
|
|
||||||
func FetchData(wc *WeatherConfig, city string) (Data, error) {
|
|
||||||
var d Data
|
|
||||||
|
|
||||||
pollTo := 30 * time.Millisecond
|
|
||||||
|
|
||||||
c := &http.Client{Timeout: pollTo * time.Second, Transport: &http.Transport{
|
|
||||||
IdleConnTimeout: pollTo,
|
|
||||||
DisableCompression: false,
|
|
||||||
}}
|
|
||||||
|
|
||||||
q := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric", city, wc.WeatherAppID)
|
|
||||||
|
|
||||||
r, err := c.Get(q)
|
|
||||||
if err != nil {
|
|
||||||
return Data{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(r.Body)
|
|
||||||
if err != nil {
|
|
||||||
return Data{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(b, &d)
|
|
||||||
if err != nil {
|
|
||||||
return Data{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.Points = map[string]interface{}{"temperature": d.Main.Temperature,
|
|
||||||
"humidity": d.Main.Humidity,
|
|
||||||
"pressure": d.Main.Pressure}
|
|
||||||
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendToInflux sends time series data to influxdb
|
|
||||||
func SendToInflux(wc *WeatherConfig, d Data) error {
|
|
||||||
|
|
||||||
httpClient, err := client.NewHTTPClient(client.HTTPConfig{
|
|
||||||
Addr: wc.InfluxURL,
|
|
||||||
Username: wc.InfluxUser,
|
|
||||||
Password: wc.InfluxPass,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer httpClient.Close()
|
|
||||||
|
|
||||||
bp, err := client.NewBatchPoints(client.BatchPointsConfig{
|
|
||||||
Database: wc.InfluxDB,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range d.Points {
|
|
||||||
tags := map[string]string{"city": d.City}
|
|
||||||
fields := map[string]interface{}{"value": value}
|
|
||||||
|
|
||||||
point, err := client.NewPoint(
|
|
||||||
key,
|
|
||||||
tags,
|
|
||||||
fields,
|
|
||||||
time.Now(),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
bp.AddPoint(point)
|
|
||||||
err = httpClient.Write(bp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage displays possible arguments
|
|
||||||
func Usage() {
|
|
||||||
flag.PrintDefaults()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
4
go.mod
4
go.mod
@ -1,6 +1,6 @@
|
|||||||
module weather
|
module git.paulbsd.com/paulbsd/weather
|
||||||
|
|
||||||
go 1.12
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
|
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
|
||||||
|
51
src/config/main.go
Normal file
51
src/config/main.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/weather/utils"
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetConfig fetch config from ini file
|
||||||
|
func GetConfig(config *Config, configfile string) error {
|
||||||
|
flag.Usage = utils.Usage
|
||||||
|
|
||||||
|
cfg, err := ini.Load(configfile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
weatherSection := cfg.Section("weather")
|
||||||
|
|
||||||
|
config.WeatherAppID = weatherSection.Key("appid").MustString("appid")
|
||||||
|
config.WeatherCities = weatherSection.Key("cities").Strings(",")
|
||||||
|
if len(config.WeatherCities) < 1 {
|
||||||
|
return fmt.Errorf("No cities provided in config")
|
||||||
|
}
|
||||||
|
config.WeatherMeasurements = weatherSection.Key("measurements").Strings(",")
|
||||||
|
if len(config.WeatherMeasurements) < 1 {
|
||||||
|
return fmt.Errorf("No measurements provided in config")
|
||||||
|
}
|
||||||
|
|
||||||
|
influxdbSection := cfg.Section("influxdb")
|
||||||
|
config.InfluxURL = influxdbSection.Key("url").MustString("http://localhost:8086")
|
||||||
|
config.InfluxUser = influxdbSection.Key("username").MustString("username")
|
||||||
|
config.InfluxPass = influxdbSection.Key("password").MustString("password")
|
||||||
|
config.InfluxDB = influxdbSection.Key("database").MustString("me")
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config is the main configuration
|
||||||
|
type Config struct {
|
||||||
|
WeatherAppID string
|
||||||
|
WeatherCities []string
|
||||||
|
WeatherMeasurements []string
|
||||||
|
InfluxURL string
|
||||||
|
InfluxAddr string
|
||||||
|
InfluxUser string
|
||||||
|
InfluxPass string
|
||||||
|
InfluxDB string
|
||||||
|
}
|
103
src/data/main.go
Normal file
103
src/data/main.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.paulbsd.com/paulbsd/weather/src/config"
|
||||||
|
client "github.com/influxdata/influxdb1-client/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FetchData fetch data from api
|
||||||
|
func FetchData(c *config.Config, city string) (Data, error) {
|
||||||
|
var d Data
|
||||||
|
|
||||||
|
pollTo := 30 * time.Millisecond
|
||||||
|
|
||||||
|
httpClient := &http.Client{Timeout: pollTo * time.Second, Transport: &http.Transport{
|
||||||
|
IdleConnTimeout: pollTo,
|
||||||
|
DisableCompression: false,
|
||||||
|
}}
|
||||||
|
|
||||||
|
q := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s&appid=%s&units=metric", city, c.WeatherAppID)
|
||||||
|
|
||||||
|
r, err := httpClient.Get(q)
|
||||||
|
if err != nil {
|
||||||
|
return Data{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return Data{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(b, &d)
|
||||||
|
if err != nil {
|
||||||
|
return Data{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Points = map[string]interface{}{"temperature": d.Main.Temperature,
|
||||||
|
"humidity": d.Main.Humidity,
|
||||||
|
"pressure": d.Main.Pressure}
|
||||||
|
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendDataToInflux sends time series data to influxdb
|
||||||
|
func SendDataToInflux(c *config.Config, d Data) error {
|
||||||
|
httpClient, err := client.NewHTTPClient(client.HTTPConfig{
|
||||||
|
Addr: c.InfluxURL,
|
||||||
|
Username: c.InfluxUser,
|
||||||
|
Password: c.InfluxPass,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer httpClient.Close()
|
||||||
|
|
||||||
|
bp, err := client.NewBatchPoints(client.BatchPointsConfig{
|
||||||
|
Database: c.InfluxDB,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range d.Points {
|
||||||
|
tags := map[string]string{"city": d.City}
|
||||||
|
fields := map[string]interface{}{"value": value}
|
||||||
|
|
||||||
|
point, err := client.NewPoint(
|
||||||
|
key,
|
||||||
|
tags,
|
||||||
|
fields,
|
||||||
|
time.Now(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bp.AddPoint(point)
|
||||||
|
err = httpClient.Write(bp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data is the struct for temperature and humidity for a city
|
||||||
|
type Data struct {
|
||||||
|
City string `json:"name"`
|
||||||
|
Main struct {
|
||||||
|
Temperature float64 `json:"temp"`
|
||||||
|
Humidity int64 `json:"humidity"`
|
||||||
|
Pressure float64 `json:"pressure"`
|
||||||
|
}
|
||||||
|
Points map[string]interface{}
|
||||||
|
}
|
24
types.go
24
types.go
@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// WeatherConfig is the main configuration
|
|
||||||
type WeatherConfig struct {
|
|
||||||
WeatherAppID string
|
|
||||||
WeatherCities []string
|
|
||||||
WeatherMeasurements []string
|
|
||||||
InfluxURL string
|
|
||||||
InfluxAddr string
|
|
||||||
InfluxUser string
|
|
||||||
InfluxPass string
|
|
||||||
InfluxDB string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data is the struct for temperature and humidity for a city
|
|
||||||
type Data struct {
|
|
||||||
City string `json:"name"`
|
|
||||||
Main struct {
|
|
||||||
Temperature float64 `json:"temp"`
|
|
||||||
Humidity int64 `json:"humidity"`
|
|
||||||
Pressure float64 `json:"pressure"`
|
|
||||||
}
|
|
||||||
Points map[string]interface{}
|
|
||||||
}
|
|
12
utils/flags.go
Normal file
12
utils/flags.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Usage displays possible arguments
|
||||||
|
func Usage() {
|
||||||
|
flag.PrintDefaults()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -1,7 +1,7 @@
|
|||||||
# github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
|
# github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
|
||||||
github.com/influxdata/influxdb1-client
|
github.com/influxdata/influxdb1-client
|
||||||
github.com/influxdata/influxdb1-client/v2
|
|
||||||
github.com/influxdata/influxdb1-client/models
|
github.com/influxdata/influxdb1-client/models
|
||||||
github.com/influxdata/influxdb1-client/pkg/escape
|
github.com/influxdata/influxdb1-client/pkg/escape
|
||||||
|
github.com/influxdata/influxdb1-client/v2
|
||||||
# gopkg.in/ini.v1 v1.44.0
|
# gopkg.in/ini.v1 v1.44.0
|
||||||
gopkg.in/ini.v1
|
gopkg.in/ini.v1
|
||||||
|
37
weather.go
37
weather.go
@ -1,37 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
_ "github.com/influxdata/influxdb1-client"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var wc WeatherConfig
|
|
||||||
var configpath string
|
|
||||||
var err error
|
|
||||||
|
|
||||||
flag.StringVar(&configpath, "configfile", "weather.ini", "config file to use with fuelprices section")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
err = GetConfig(&wc, configpath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, city := range wc.WeatherCities {
|
|
||||||
d, err := FetchData(&wc, city)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = SendToInflux(&wc, d)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
} else {
|
|
||||||
log.Println(fmt.Sprintf("Successfully sent data for %s", city))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user