diff --git a/README.md b/README.md index 2cd7e0b..f443cc5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,30 @@ # humiditycalc +BOTH slow- every req talks to api + ## ENV MODES: CALC, WEATHER, BOTH BOTH is standard -OPENWEATHERMAP_API_KEY is required in WEATHER and BOTH mode \ No newline at end of file +OPENWEATHERMAP_API_KEY is required in WEATHER and BOTH mode + +DEFAULT: +MODE=CALC + +Standalone: +MODE=BOTH +OPENWEATHERMAP_API_KEY=yourkey +LATITUDE= +LONGITUDE= + +WEATHER: +MODE=WEATHER +OPENWEATHERMAP_API_KEY=yourkey +DB_HOST= +DB_PORT= +DB_NAME= +DB_PASSWORD= +DB= + +OPTINAL: +PORT=80 \ No newline at end of file diff --git a/internal/weather.go b/internal/weather.go index 5bf0569..ad6d162 100644 --- a/internal/weather.go +++ b/internal/weather.go @@ -1 +1,68 @@ package internal + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" +) + +func Weather(env map[string]string) (humidity float64, temperature float64) { + // Get API key from environment variables + apiKey := env["OPENWEATHERMAP_API_KEY"] + + // Get latitude and longitude from environment variables + latitude := env["LATITUDE"] + longitude := env["LONGITUDE"] + + // Check if latitude and longitude are set + if latitude == "" || longitude == "" { + fmt.Println("Latitude and longitude are not set") + os.Exit(1) + } + + // Get data from API + data := getData(apiKey, latitude, longitude) + + // Parse data + humidity, temperature = parseData(data) + + // Convert to Celsius + temperature = temperature - 273.15 + + return humidity, temperature + +} + +func getData(apiKey string, latitude string, longitude string) string { + // Get data from API + url := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?lat=%s&lon=%s&appid=%s", latitude, longitude, apiKey) + resp, err := http.Get(url) + if err != nil { + fmt.Println("Error getting data from API") + } + defer resp.Body.Close() + + // Read response body + body, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading response body") + } + + // Convert body to string + return string(body) +} + +func parseData(data string) (humidity float64, temperature float64) { + // Parse data from API + + m := make(map[string]interface{}) + err := json.Unmarshal([]byte(data), &m) + if err != nil { + fmt.Println("Error parsing data") + } + n := m["main"].(map[string]interface{}) + + return n["humidity"].(float64), n["temp"].(float64) +} diff --git a/main.go b/main.go index 0896e87..26bbc51 100644 --- a/main.go +++ b/main.go @@ -14,14 +14,17 @@ func main() { if val, ok := env["MODE"]; ok { if strings.ToLower(val) == "both" { checkEnv(env) - server.Run() + server.Run(env) } else if strings.ToLower(val) == "weather" { checkEnv(env) // weather.Run() } else if strings.ToLower(val) == "calc" { // calc.Run() - server.Run() + server.Run(env) } + } else { + // calc.Run() + server.Run(env) } } @@ -42,7 +45,6 @@ func loadEnv() map[string]string { func checkEnv(env map[string]string) { // Is there an API key for openweathermap? if val, ok := env["OPENWEATHERMAP_API_KEY"]; ok { - fmt.Println(val) if val == "" { print("OPENWEATHERMAP_API_KEY is not set") os.Exit(1) diff --git a/models/cache.go b/models/cache.go new file mode 100644 index 0000000..57e8c27 --- /dev/null +++ b/models/cache.go @@ -0,0 +1,36 @@ +package models + +import ( + "fmt" + "time" +) + +type WeatherCache struct { + Humidity float64 // relative humidity in percentage + Temperature float64 // temperature in Celsius + timestamp time.Time // timestamp of last update + duration int16 // duration in seconds +} + +func (w *WeatherCache) IsExpired() bool { + fmt.Println(time.Since(w.timestamp), time.Duration(w.duration)*time.Second) + return time.Since(w.timestamp) > time.Duration(w.duration)*time.Second +} + +func (w *WeatherCache) SetData(humidity float64, temperature float64) { + w.Humidity = humidity + w.Temperature = temperature + w.timestamp = time.Now() + w.duration = 60 +} + +func (w *WeatherCache) GetData() (float64, float64) { + if w.IsExpired() { + return 0, 0 + } + return w.Humidity, w.Temperature +} + +func NewWeatherCache() *WeatherCache { + return &WeatherCache{} +} diff --git a/server/server.go b/server/server.go index f6aaf07..784e5a6 100644 --- a/server/server.go +++ b/server/server.go @@ -1,19 +1,33 @@ package server import ( + "fmt" "html/template" "net/http" "strconv" + "strings" "github.com/LeRoid-hub/humiditycalc/internal" + "github.com/LeRoid-hub/humiditycalc/models" ) type result struct { - AbsoluteHumidity float64 + AbsoluteHumidity string + WeatherData WeatherData +} + +type WeatherData struct { + Temperature string + RelativeHumidity string + AbsoluteHumidity string } // Run starts the HTTP server. -func Run() { +func Run(env map[string]string) { + // Cache weather data + var cacheWeather = models.NewWeatherCache() + + // Load HTML template tmpl := template.Must(template.ParseFiles("./web/templates/index.html")) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { @@ -39,10 +53,44 @@ func Run() { // Calculate absolute humidity absoluteHumidity := internal.AbsoluteHumidity(temp, rh) + var absoluteWeatherHumidity float64 + var temperature, humidity float64 + + // Check if cache is expired or empty + if cacheWeather.IsExpired() || cacheWeather.Humidity == 0 || cacheWeather.Temperature == 0 { + // Get Weather data + humidity, temperature := internal.Weather(env) + + // Calculate absolute weather humidity + absoluteWeatherHumidity = internal.AbsoluteHumidity(temperature, humidity) + + // Update cache + cacheWeather.SetData(humidity, temperature) + } else { + // Use cached data + humidity, temperature := cacheWeather.GetData() + absoluteWeatherHumidity = internal.AbsoluteHumidity(temperature, humidity) + } + + // Create response + WData := WeatherData{Temperature: FormatFloat(temperature, 2), RelativeHumidity: FormatFloat(humidity, 4), AbsoluteHumidity: FormatFloat(absoluteWeatherHumidity, 4)} + + re := result{AbsoluteHumidity: FormatFloat(absoluteHumidity, 4), WeatherData: WData} + // Write response - tmpl.Execute(w, result{AbsoluteHumidity: absoluteHumidity}) + tmpl.Execute(w, re) }) http.ListenAndServe(":8080", nil) } + +func FormatFloat(num float64, prc int) string { + var ( + zero, dot = "0", "." + + str = fmt.Sprintf("%."+strconv.Itoa(prc)+"f", num) + ) + + return strings.TrimRight(strings.TrimRight(str, zero), dot) +} diff --git a/web/templates/index.html b/web/templates/index.html index 337664c..deca291 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -14,7 +14,15 @@
+ + {{ if .WeatherData }} +

Weather Data

+

Temperature: {{ .WeatherData.Temperature }}°C

+

Relative Humidity: {{ .WeatherData.RelativeHumidity }}%

+

Absolute Humidity: {{ .WeatherData.AbsoluteHumidity }} g/m³

+ {{ end }} {{ if .AbsoluteHumidity }} +

Calculated Absolute Humidity

Absolute Humidity: {{ .AbsoluteHumidity }} g/m³

{{ end }}