refactored weather

This commit is contained in:
Paul 2020-02-04 22:21:21 +01:00
parent fb6acf48f8
commit 546f80cfce
10 changed files with 190 additions and 202 deletions

18
Makefile Normal file
View 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}

View File

@ -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

View File

@ -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
View File

@ -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
View 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
View 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{}
}

View File

@ -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
View 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
View File

@ -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

View File

@ -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))
}
}
}