rewrite weather in go
This commit is contained in:
parent
65297845e5
commit
605d340aa0
24
flake.nix
24
flake.nix
|
@ -94,6 +94,7 @@
|
|||
deploy-rs-pkg = null;
|
||||
})
|
||||
(_: super: {
|
||||
weather = super.callPackage ./pkgs/weather { };
|
||||
nicer = super.callPackage ./pkgs/nicer.nix { };
|
||||
imapsync = super.callPackage ./pkgs/imapsync.nix { };
|
||||
tmuxbash = super.callPackage ./pkgs/tmuxbash.nix { };
|
||||
|
@ -305,19 +306,20 @@
|
|||
};
|
||||
|
||||
formatter = pkgs.nixfmt-rfc-style;
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
// {
|
||||
packages.x86_64-linux.vanta-agent =
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit overlays;
|
||||
system = "x86_64-linux";
|
||||
};
|
||||
in
|
||||
pkgs.vanta-agent;
|
||||
};
|
||||
// (
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit overlays;
|
||||
system = "x86_64-linux";
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.x86_64-linux.vanta-agent = pkgs.vanta-agent;
|
||||
packages.x86_64-linux.weather = pkgs.weather;
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -95,8 +95,8 @@ in
|
|||
bash
|
||||
];
|
||||
serviceConfig = {
|
||||
type = "notify";
|
||||
ExecStart = "${pkgs.systemd}/bin/systemd-socket-activate -a --inetd -l ${toString myData.ports.exporters.weather} ${../../pkgs/weather/main}";
|
||||
type = "simple";
|
||||
ExecStart = "${pkgs.weather}/bin/weather";
|
||||
ProtectSystem = "strict";
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{ buildGoModule }:
|
||||
buildGoModule {
|
||||
name = "weather";
|
||||
src = ./.;
|
||||
vendorHash = null;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module git.jakstys.lt/motiejus/config/pkgs/weather
|
||||
|
||||
go 1.19
|
|
@ -1,43 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
STATION=vilniaus-ams
|
||||
TODAY=${1:-$(date +%F)}
|
||||
|
||||
export TZ=UTC
|
||||
sed -e 's/$/\r/' <<EOF
|
||||
HTTP/1.0 200 OK
|
||||
Content-Type: text/plain; version=0.0.4; charset=utf-8; escaping=values
|
||||
|
||||
EOF
|
||||
|
||||
get() { jq -r ".$1 // 0" <<< "$2"; }
|
||||
|
||||
while IFS= read -r obs; do
|
||||
#{
|
||||
# "observationTimeUtc": "2024-09-13 12:00:00",
|
||||
# "airTemperature": 20.9,
|
||||
# "feelsLikeTemperature": 20.9,
|
||||
# "windSpeed": 1.4,
|
||||
# "windGust": 5.7,
|
||||
# "windDirection": 103,
|
||||
# "cloudCover": 88,
|
||||
# "seaLevelPressure": 1010.3,
|
||||
# "relativeHumidity": 82,
|
||||
# "precipitation": 0,
|
||||
# "conditionCode": "rain"
|
||||
#}
|
||||
ts=$(date +%s000 --date="$(get observationTimeUtc "$obs")")
|
||||
cat <<EOF
|
||||
weather_station_air_temperature_celsius{station="$STATION"} $(get airTemperature "$obs") $ts
|
||||
weather_station_air_feels_like_celsius{station="$STATION"} $(get feelsLikeTemperature "$obs") $ts
|
||||
weather_station_wind_speed_ms{station="$STATION"} $(get windSpeed "$obs") $ts
|
||||
weather_station_wind_gust_ms{station="$STATION"} $(get windGust "$obs") $ts
|
||||
weather_station_wind_direction_degrees{station="$STATION"} $(get windDirection "$obs") $ts
|
||||
weather_station_cloud_cover_percent{station="$STATION"} $(get cloudCover "$obs") $ts
|
||||
weather_station_sea_level_pressure_hpa{station="$STATION"} $(get seaLevelPressure "$obs") $ts
|
||||
weather_station_relative_humidity_percent{station="$STATION"} $(get relativeHumidity "$obs") $ts
|
||||
weather_station_precipitation_mm{station="$STATION"} $(get precipitation "$obs") $ts
|
||||
weather_station_condition{station="$STATION",code="$(get conditionCode "$obs")"} 1 $ts
|
||||
EOF
|
||||
done < <(curl -f -s "https://api.meteo.lt/v1/stations/$STATION/observations/$TODAY" | jq -c '.observations[]')
|
|
@ -0,0 +1,118 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
_listen = ":9011"
|
||||
_urlTemplate = "https://api.meteo.lt/v1/stations/%s/observations/%s"
|
||||
_station = "vilniaus-ams"
|
||||
_promTemplate = `weather_station_air_temperature_celsius{station="{{ .Station }}"} {{ .AirTemperature }} {{ .TS }}
|
||||
weather_station_air_feels_like_celsius{station="{{ .Station }}"} {{ .FeelsLikeTemperature }} {{ .TS }}
|
||||
weather_station_wind_speed_ms{station="{{ .Station }}"} {{ .WindSpeed }} {{ .TS }}
|
||||
weather_station_wind_gust_ms{station="{{ .Station }}"} {{ .WindGust }} {{ .TS }}
|
||||
weather_station_wind_direction_degrees{station="{{ .Station }}"} {{ .WindDirection }} {{ .TS }}{{ if .CloudCover }}
|
||||
weather_station_cloud_cover_percent{station="{{ .Station }}"} {{ .CloudCover }} {{ .TS }}{{ end }}
|
||||
weather_station_sea_level_pressure_hpa{station="{{ .Station }}"} {{ .SeaLevelPressure }} {{ .TS }}
|
||||
weather_station_relative_humidity_percent{station="{{ .Station }}"} {{ .RelativeHumidity }} {{ .TS }}
|
||||
weather_station_precipitation_mm{station="{{ .Station }}"} {{ .Precipitation }} {{ .TS }}{{ if .ConditionCode }}
|
||||
weather_station_condition{station="{{ .Station }}",code="{{ .ConditionCode }}"} 1 {{ .TS }}{{ end }}
|
||||
`
|
||||
)
|
||||
|
||||
var tpl = template.Must(template.New("prom").Parse(_promTemplate))
|
||||
|
||||
func main() {
|
||||
log.Printf("Listening on %s\n", _listen)
|
||||
log.Fatal((&http.Server{
|
||||
Addr: _listen,
|
||||
Handler: http.HandlerFunc(handler),
|
||||
}).ListenAndServe())
|
||||
}
|
||||
|
||||
type observation struct {
|
||||
ObservationTimeUtc string `json:"observationTimeUtc"`
|
||||
AirTemperature float64 `json:"airTemperature"`
|
||||
FeelsLikeTemperature float64 `json:"feelsLikeTemperature"`
|
||||
WindSpeed float64 `json:"windSpeed"`
|
||||
WindGust float64 `json:"windGust"`
|
||||
WindDirection float64 `json:"windDirection"`
|
||||
CloudCover *float64 `json:"cloudCover"`
|
||||
SeaLevelPressure float64 `json:"seaLevelPressure"`
|
||||
RelativeHumidity float64 `json:"relativeHumidity"`
|
||||
Precipitation float64 `json:"precipitation"`
|
||||
ConditionCode *string `json:"conditionCode"`
|
||||
|
||||
// template variables
|
||||
TS int64
|
||||
Station string
|
||||
}
|
||||
|
||||
func handler(w http.ResponseWriter, r *http.Request) {
|
||||
observations, err := getObservations(time.Now().UTC(), _station)
|
||||
if err != nil {
|
||||
log.Printf("Error getting observations: %v\n", err)
|
||||
http.Error(w, fmt.Sprintf("Internal error: %v", err.Error()), 500)
|
||||
return
|
||||
}
|
||||
w.Header().Add("Content-Type", "text/plain; version=0.0.4")
|
||||
|
||||
bw := bufio.NewWriter(w)
|
||||
defer bw.Flush()
|
||||
|
||||
for _, observation := range observations {
|
||||
|
||||
ts, err := time.ParseInLocation(
|
||||
time.DateTime,
|
||||
observation.ObservationTimeUtc,
|
||||
time.UTC,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("error parsing time %q: %v\n", observation.ObservationTimeUtc, err)
|
||||
return
|
||||
}
|
||||
observation.TS = ts.UnixMilli()
|
||||
observation.Station = _station
|
||||
|
||||
if err := tpl.Execute(bw, observation); err != nil {
|
||||
log.Printf("error executing template: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
bw.WriteString("\n")
|
||||
}
|
||||
|
||||
func getObservations(date time.Time, station string) ([]observation, error) {
|
||||
url := fmt.Sprintf(_urlTemplate, station, date.Format(time.DateOnly))
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get %q: %w", url, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
io.Copy(io.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("got non-200 http status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(resp.Body)
|
||||
var incoming struct {
|
||||
Observations []observation `json:"observations"`
|
||||
}
|
||||
if err := decoder.Decode(&incoming); err != nil {
|
||||
return nil, fmt.Errorf("json decode: %w", err)
|
||||
}
|
||||
|
||||
return incoming.Observations, nil
|
||||
}
|
Loading…
Reference in New Issue