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

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

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