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
|
||||
|
||||
```bash
|
||||
go build -mod=vendor
|
||||
make
|
||||
```
|
||||
|
||||
### Sample config in weather.ini
|
||||
@ -38,7 +38,7 @@ measurements=temp,humidity,pressure
|
||||
|
||||
## License
|
||||
```text
|
||||
Copyright (c) 2019, PaulBSD
|
||||
Copyright (c) 2020, PaulBSD
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
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 (
|
||||
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
|
||||
github.com/influxdata/influxdb1-client/v2
|
||||
github.com/influxdata/influxdb1-client/models
|
||||
github.com/influxdata/influxdb1-client/pkg/escape
|
||||
github.com/influxdata/influxdb1-client/v2
|
||||
# gopkg.in/ini.v1 v1.44.0
|
||||
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