-
Notifications
You must be signed in to change notification settings - Fork 0
API
This page will show you how the API parser works, how the OpenMeteo API works and how do functions which directly use the API work.
The API Parser is a function that expects five arguments, that being latitude, longitude, city, country and units. The city and country are not needed really, but when refactoring it made sense, since the return value is an associative array.
Units are needed as I wanted to include both imperial and metric units.
case $UNITS in
imp)
TEMP_U="&temperature_unit=fahrenheit"
WIND_U="&wind_speed_unit=mph"
PREC_U="&precipitation_unit=inch"
;;
met)
TEMP_U=""
WIND_U=""
PREC_U=""
;;
esacHere's the code for parsing units. I selected Fahrenheit, mph (wind) and inch (rain) for the imperial units. Metric units may be left empty as OpenMeteoAPI defaults to metric.
The API URL is quite long so I will split it up.
WTHR_API=$(curl -s "https://api.open-meteo.com/v1/forecast?\
latitude=$LAT&longitude=$LONG¤t=temperature_2m,relative_humidity_2m,\
precipitation,cloud_cover,wind_speed_10m,wind_direction_10m,wind_gusts_10m,\
is_day,weather_code&timezone=auto$TEMP_U$WIND_U$PREC_U" | jq -c)It expects Latitude and Longitude and optionally Units. wayweather is getting the Temperature, Humidity, Precipitation, Cloud Cover, Wind Speed, Gusts and Direction, Day or Night and Weather Code. The last two ones are for the NerdFonts icon.
Parsing of the response is between the lines 28-34 in src/meteo_api and will not be explained here, as it's basic jq and awk parsing.
Wind Direction is parsed into letters via:
WIND_ARR=(
"North"
"North East"
"East"
"South East"
"South"
"South West"
"West"
"North West"
)
WIND_DIR="$(echo "$WTHR_API" | jq -r '.current.wind_direction_10m')"
WIND_DIR_LET="${WIND_ARR[$(echo "$WIND_DIR" | awk '{print int(($1 / 45) % 8 )}')]}"The calculation is not my creation, as I found it on a code sharing website.
The Icons are an Associative array of weather codes from openmeteo and corresponding weather icons from NerdFonts. The code is on line 54 in src/meteo_api.
The last part is adding all elements into an array.
WTHR=(
["CITY"]=$CITY
["COUNTRY"]=$COUNTRY
["TIME"]=$TIME
["TEMP"]=$TEMP
["HUMID"]=$HUMID
["PREC"]=$PREC
["CLOUD"]=$CLOUD
["WIND_S"]=$WIND_S
["WIND_G"]=$WIND_G
["WIND_DIR"]="$WIND_DIR_LET ($WIND_DIR°)"
["WI"]=$WI
)
printf "%s " "${WTHR[@]@K}"The return code was copied from some nice user on stackoverflow, as it keeps the array assiociative.
The help message for --get is
> wayweather [-g/--get] [--no-icon]
OPTIONS:
--no-icon Return a waybar parsable
json string withou a NerdFont
icon
Returns a compact JSON string for the waybar
module. It is not human readable.
Use with a restart interval.
EXAMPLE:
> wayweather --get
{"text":"71.1°F <big> </big>","tooltip":"New York, USA\nTime: 2025-09-30 19:45\n\n
Temperature: 71.1°F\nHumidity: 53%\nPrecipitaion: 0.00 inch\nCloud Cover: 19%\n
Wind Direct: North West (356°)\nWind Speed: 6.3 mph\nWind Gusts: 15.2 mph"}
Both --get and --print support disabling the icon if you do not want it.
You will not see the icon between <big> </big> as you need a NerdFont Patched font.
The help from --print is
> wayweather [-p/--print] [--no-icon]
OPTIONS:
--no-icon Disables the weather icon
from NerdFonts
Prints the waybar result to stdout in a human
readable format.
For testing purposes
This one does not have much information in it, just some basics.
The code that results in the Waybar JSON is
ICON="$(if $NO_ICON; then echo ""; else echo " <big>${WTHR_ARR["WI"]}</big>"; fi)"
echo "{'text': '${WTHR_ARR["TEMP"]}$ICON'\
,'tooltip': '${WTHR_ARR["CITY"]}, ${WTHR_ARR["COUNTRY"]}\
\nTime: ${WTHR_ARR["TIME"]}\n\nTemperature: ${WTHR_ARR["TEMP"]}\
\nHumidity: ${WTHR_ARR["HUMID"]}\nPrecipitaion: ${WTHR_ARR["PREC"]}\
\nCloud Cover: ${WTHR_ARR["CLOUD"]}\nWind Direct: ${WTHR_ARR["WIND_DIR"]}\
\nWind Speed: ${WTHR_ARR["WIND_S"]}\nWind Gusts: ${WTHR_ARR["WIND_G"]}'}" | sed -e "s/'/\"/g" | jq -cOther that boolean based if statement for the icon, the only fun thing is the sed command (I didn't want to \" the double quotes)
The result for --print is much more readable
echo "TEXT:
${WTHR_ARR["TEMP"]}$ICON
TOOLTIP:
${WTHR_ARR["CITY"]}, ${WTHR_ARR["COUNTRY"]}
Time: ${WTHR_ARR["TIME"]}
Temperature: ${WTHR_ARR["TEMP"]}
Humidity: ${WTHR_ARR["HUMID"]}
Precipitaion: ${WTHR_ARR["PREC"]}
Cloud Cover: ${WTHR_ARR["CLOUD"]}
Wind Direct: ${WTHR_ARR["WIND_DIR"]}
Wind Speed: ${WTHR_ARR["WIND_S"]}
Wind Gusts: ${WTHR_ARR["WIND_G"]}"The Text is what is visible in Waybar and Tooltip when hovering the module.
The daemon is a looping system printing waybar json on config change.
> wayweather [-w/--daemon] [OPTIONS]
OPTIONS:
--no-icon Disables the weather icon
from NerdFonts
--location=NUM Expects a location ID from --list
Will load the location into
config and use it
--timer=NUM Expects the amount of seconds
the daemon should wait before
checking changes in config
Default: 15, Recommended: 5 - 30
Runs a loop with the same components as --get but
checks changes in the config so the API is not
polled every time.
The check is done in three parts, so that is has
redundancy and has a 15 minute timer for API
updates.
Returns a stream of waybar parsable JSON strings.
You can change the default location via an ID from --load and change the config checking timer.
The location check is just an integer checker with existence checker, that later run load with the ID
location=*)
LOCATION="${i#*=}"
if [[ "$LOCATION" =~ ^[0-9]+$ ]]; then
ID=false
for key in $(cat "$SAVE_PATH" | jq -rc 'keys | @sh' | tr -d \'); do
if [[ "$LOCATION" -eq "$key" ]]; then
ID=true
fi
done
if $ID; then
load_loc "$LOCATION"
fi
fiThe checker uses three step process, so that it catches the config change every time. It is just a few comparisons in a config history array. There is also a loop checking if the next quarter hour has passed for api pulling.
unset HISTORY
declare -A HISTORY
HISTORY["0"]="NONE"
HISTORY["1"]="NONE"
HISTORY["2"]="NONE"
UPDATE=false
.......
while true; do
HISTORY["0"]="$(cat "$CONF_PATH")"
if [[ "${HISTORY["1"]}" != "NONE" && "${HISTORY["2"]}" != "NONE" ]] && [[ "${HISTORY["0"]}" != "${HISTORY["1"]}" || "${HISTORY["0"]}" != "${HISTORY["2"]}" || "${HISTORY["1"]}" != "${HISTORY["2"]}" ]]; then
break
fi
sleep "$((SLEEP / 2))s"
HISTORY["1"]="$(cat "$CONF_PATH")"
if [[ "${HISTORY["2"]}" != "NONE" ]] && [[ "${HISTORY["0"]}" != "${HISTORY["1"]}" || "${HISTORY["0"]}" != "${HISTORY["2"]}" || "${HISTORY["1"]}" != "${HISTORY["2"]}" ]]; then
break
fi
sleep "$((SLEEP / 2))s"
HISTORY["2"]="$(cat "$CONF_PATH")"
if [[ "${HISTORY["0"]}" != "${HISTORY["1"]}" || "${HISTORY["0"]}" != "${HISTORY["2"]}" || "${HISTORY["1"]}" != "${HISTORY["2"]}" ]]; then
break
fi
for i in $(seq 0 4); do
if [[ "$(($(date +"%M") - $((15 * i))))" == "0" ]]; then
UPDATE=true
fi
done
if $UPDATE; then
break
fi
done