Editited html, pull weather, mode both works, weatherdata cache

This commit is contained in:
Jan 2024-11-02 18:10:52 +01:00
parent 80cdd9de4f
commit c0049aa393
6 changed files with 191 additions and 7 deletions

View File

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

View File

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

View File

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

36
models/cache.go Normal file
View File

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

View File

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

View File

@ -14,7 +14,15 @@
<br>
<button type="submit">Calculate</button>
</form>
{{ if .WeatherData }}
<h2>Weather Data</h2>
<p>Temperature: {{ .WeatherData.Temperature }}°C</p>
<p>Relative Humidity: {{ .WeatherData.RelativeHumidity }}%</p>
<p>Absolute Humidity: {{ .WeatherData.AbsoluteHumidity }} g/m³</p>
{{ end }}
{{ if .AbsoluteHumidity }}
<h2>Calculated Absolute Humidity</h2>
<p>Absolute Humidity: {{ .AbsoluteHumidity }} g/m³</p>
{{ end }}
</body>