#!/bin/bash
# SETTINGS vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
source "$HOME/.cache/m3-colors/colors.sh"
# API settings ________________________________________________________________
# Open-Meteo
CITY_NAME='Naperville'
COUNTRY_CODE='ID'
# FILL WITH LATITUDE AND LONGITUDE
LATITUDE="-6.17511" # Semarang latitude
LONGITUDE="106.86504" # Semarang longitude
# Desired output language
LANG="en"
# UNITS: "metric" or "imperial"
UNITS="metric"
# Color Settings ______________________________________________________________
COLOR_CLOUD="$color7"
COLOR_THUNDER="$color7"
COLOR_LIGHT_RAIN="$color7"
COLOR_HEAVY_RAIN="$color7"
COLOR_SNOW="$color7"
COLOR_FOG="$color7"
COLOR_TORNADO="$color7"
COLOR_SUN="$color7"
COLOR_MOON="$color7"
COLOR_ERR="$color7"
COLOR_WIND="$color7"
COLOR_COLD="$color7"
COLOR_HOT="$color7"
COLOR_NORMAL_TEMP="$color7"
COLOR_TEXT=""
# Polybar settings ____________________________________________________________
# Font for the weather icons
WEATHER_FONT_CODE=2
# Font for the thermometer icon
TEMP_FONT_CODE=2
# Wind settings _______________________________________________________________
# Display info about the wind or not. yes/no
DISPLAY_WIND="yes"
# Show beaufort level in windicon
BEAUFORTICON="yes"
# Display in knots. yes/no
KNOTS="yes"
# How many decimals after the floating point
DECIMALS=0
# Min. wind force required to display wind info
MIN_WIND=11
# Display the numeric wind force or not. yes/no
DISPLAY_FORCE="yes"
# Display the wind unit if wind force is displayed. yes/no
DISPLAY_WIND_UNIT="yes"
# Thermometer settings ________________________________________________________
# When the thermometer icon turns red
HOT_TEMP=25
# When the thermometer icon turns blue
COLD_TEMP=0
# Other settings ______________________________________________________________
# Display the weather description. yes/no
DISPLAY_LABEL="yes"
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
if [ "$COLOR_TEXT" != "" ]; then
COLOR_TEXT_BEGIN="%{F$COLOR_TEXT}"
COLOR_TEXT_END="%{F-}"
fi
# Jika latitude/longitude tidak diisi, coba gunakan geocoding
if [ -z "$LATITUDE" ] || [ -z "$LONGITUDE" ]; then
if [ -z "$CITY_NAME" ]; then
# Jika city juga kosong, gunakan IP location
IP=`curl -s ifconfig.me`
IPCURL=$(curl -s https://ipinfo.io/$IP)
CITY_NAME=$(echo $IPCURL | jq -r ".city")
COUNTRY_CODE=$(echo $IPCURL | jq -r ".country")
fi
# Gunakan Open-Meteo Geocoding API untuk mendapatkan koordinat
GEOCODE_URL="https://geocoding-api.open-meteo.com/v1/search?name=$CITY_NAME&count=1&language=en&format=json"
GEOCODE_RESPONSE=`curl -s "$GEOCODE_URL"`
if [ "$1" = "-d" ]; then
echo "Geocoding response: $GEOCODE_RESPONSE"
fi
LATITUDE=$(echo $GEOCODE_RESPONSE | jq -r '.results[0].latitude')
LONGITUDE=$(echo $GEOCODE_RESPONSE | jq -r '.results[0].longitude')
if [ "$LATITUDE" = "null" ] || [ "$LONGITUDE" = "null" ]; then
echo "Error: Could not find coordinates for $CITY_NAME"
exit 1
fi
fi
RESPONSE=""
ERROR=0
ERR_MSG=""
# Temperature unit untuk Open-Meteo
if [ "$UNITS" = "imperial" ]; then
TEMP_UNIT_PARAM="temperature_unit=fahrenheit"
else
TEMP_UNIT_PARAM="temperature_unit=celsius"
fi
# Wind speed unit untuk Open-Meteo
if [ $KNOTS == "yes" ]; then
WIND_UNIT_PARAM="windspeed_unit=kn"
elif [ "$UNITS" = "imperial" ]; then
WIND_UNIT_PARAM="windspeed_unit=mph"
else
WIND_UNIT_PARAM="windspeed_unit=kmh"
fi
# Open-Meteo API URL
URL="https://api.open-meteo.com/v1/forecast?latitude=$LATITUDE&longitude=$LONGITUDE¤t=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m&daily=sunrise,sunset&${TEMP_UNIT_PARAM}&${WIND_UNIT_PARAM}&timezone=auto"
function getData {
ERROR=0
RESPONSE=`curl -s "$URL"`
CODE="$?"
if [ "$1" = "-d" ]; then
echo "URL: $URL"
echo "Response: $RESPONSE"
echo ""
fi
if [ $CODE -ne 0 ]; then
ERR_MSG="curl Error $CODE"
ERROR=1
elif [ -z "$RESPONSE" ]; then
ERR_MSG="Empty Response"
ERROR=1
else
# Check if response contains error
HAS_ERROR=$(echo $RESPONSE | jq -r '.error // false')
if [ "$HAS_ERROR" = "true" ]; then
ERR_MSG="API Error"
ERROR=1
fi
fi
}
function setIcons {
# WMO Weather interpretation codes (WW)
# 0: Clear sky
# 1-3: Mainly clear, partly cloudy, and overcast
# 45, 48: Fog
# 51-57: Drizzle
# 61-67: Rain
# 71-77: Snow
# 80-82: Rain showers
# 85-86: Snow showers
# 95-99: Thunderstorm
WID=$1
DATE=$(date +%s)
if [ $WID -ge 95 ]; then
# Thunderstorm
ICON_COLOR=$COLOR_THUNDER
if [ $DATE -ge $SUNRISE -a $DATE -le $SUNSET ]; then
ICON=" "
else
ICON=" "
fi
elif [ $WID -ge 85 ]; then
# Snow showers
ICON_COLOR=$COLOR_SNOW
ICON=" "
elif [ $WID -ge 80 ]; then
# Rain showers
ICON_COLOR=$COLOR_HEAVY_RAIN
if [ $DATE -ge $SUNRISE -a $DATE -le $SUNSET ]; then
ICON="殺"
else
ICON="殺"
fi
elif [ $WID -ge 71 ]; then
# Snow
ICON_COLOR=$COLOR_SNOW
ICON=" "
elif [ $WID -ge 61 ]; then
# Rain
ICON_COLOR=$COLOR_HEAVY_RAIN
if [ $DATE -ge $SUNRISE -a $DATE -le $SUNSET ]; then
ICON=" "
else
ICON=" "
fi
elif [ $WID -ge 51 ]; then
# Drizzle
ICON_COLOR=$COLOR_LIGHT_RAIN
if [ $DATE -ge $SUNRISE -a $DATE -le $SUNSET ]; then
ICON=" "
else
ICON=" "
fi
elif [ $WID -ge 45 ]; then
# Fog
ICON_COLOR=$COLOR_FOG
ICON=" "
elif [ $WID -eq 0 ]; then
# Clear sky
if [ $DATE -ge $SUNRISE -a $DATE -le $SUNSET ]; then
ICON_COLOR=$COLOR_SUN
ICON=" "
else
ICON_COLOR=$COLOR_MOON
ICON=" "
fi
elif [ $WID -ge 1 ] && [ $WID -le 3 ]; then
# Partly cloudy to overcast
if [ $WID -eq 1 ]; then
# Few clouds
if [ $DATE -ge $SUNRISE -a $DATE -le $SUNSET ]; then
ICON_COLOR=$COLOR_SUN
ICON=" "
else
ICON_COLOR=$COLOR_MOON
ICON=" "
fi
else
# Overcast
ICON_COLOR=$COLOR_CLOUD
ICON=" "
fi
else
ICON_COLOR=$COLOR_ERR
ICON=" "
fi
WIND=""
WINDFORCE=$WINDFORCE_ACTUAL
WINDICON=" "
if [ $BEAUFORTICON == "yes" ]; then
# Convert to km/h for Beaufort calculation
if [ $KNOTS == "yes" ]; then
WINDFORCE2=$(echo "scale=2;$WINDFORCE_ACTUAL * 1.852 / 1" | bc)
elif [ "$UNITS" = "imperial" ]; then
WINDFORCE2=$(echo "scale=2;$WINDFORCE_ACTUAL * 1.60934 / 1" | bc)
else
WINDFORCE2=$WINDFORCE_ACTUAL
fi
if (( $(echo "$WINDFORCE2 <= 1" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 1 && $WINDFORCE2 <= 5" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 5 && $WINDFORCE2 <= 11" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 11 && $WINDFORCE2 <= 19" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 19 && $WINDFORCE2 <= 28" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 28 && $WINDFORCE2 <= 38" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 38 && $WINDFORCE2 <= 49" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 49 && $WINDFORCE2 <= 61" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 61 && $WINDFORCE2 <= 74" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 74 && $WINDFORCE2 <= 88" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 88 && $WINDFORCE2 <= 102" | bc -l) )); then
WINDICON=" "
elif (( $(echo "$WINDFORCE2 > 102 && $WINDFORCE2 <= 117" | bc -l) )); then
WINDICON=" "
else
WINDICON=" "
fi
fi
WINDFORCE=$(echo "scale=$DECIMALS;$WINDFORCE / 1" | bc)
if [ "$DISPLAY_WIND" == "yes" ] && (( $(echo "$WINDFORCE >= $MIN_WIND" | bc -l) )); then
WIND="%{T$WEATHER_FONT_CODE}%{F$COLOR_WIND}$WINDICON%{F-}%{T-}"
if [ "$DISPLAY_FORCE" == "yes" ]; then
WIND="$WIND $COLOR_TEXT_BEGIN$WINDFORCE$COLOR_TEXT_END"
if [ "$DISPLAY_WIND_UNIT" == "yes" ]; then
if [ $KNOTS == "yes" ]; then
WIND="$WIND ${COLOR_TEXT_BEGIN}kn$COLOR_TEXT_END"
elif [ $UNITS == "imperial" ]; then
WIND="$WIND ${COLOR_TEXT_BEGIN}mph$COLOR_TEXT_END"
else
WIND="$WIND ${COLOR_TEXT_BEGIN}km/h$COLOR_TEXT_END"
fi
fi
fi
WIND="$WIND |"
fi
if [ "$UNITS" == "imperial" ]; then
TEMP_UNIT="°F"
else
TEMP_UNIT="°C"
fi
TEMP=$(echo "$TEMP" | cut -d "." -f 1)
if [ "$TEMP" -le $COLD_TEMP ]; then
TEMP="%{F$COLOR_COLD}%{T$TEMP_FONT_CODE}%{T-}%{F-} $COLOR_TEXT_BEGIN$TEMP%{T$TEMP_FONT_CODE}$TEMP_ICON%{T-}$TEMP_UNIT$COLOR_TEXT_END"
elif (( $(echo "$TEMP >= $HOT_TEMP" | bc -l) )); then
TEMP="%{F$COLOR_HOT}%{T$TEMP_FONT_CODE}%{T-}%{F-} $COLOR_TEXT_BEGIN$TEMP%{T$TEMP_FONT_CODE}$TEMP_ICON%{T-}$TEMP_UNIT$COLOR_TEXT_END"
else
TEMP="%{F$COLOR_NORMAL_TEMP}%{T$TEMP_FONT_CODE}%{T-}%{F-} $COLOR_TEXT_BEGIN$TEMP%{T$TEMP_FONT_CODE}$TEMP_ICON%{T-}$TEMP_UNIT$COLOR_TEXT_END"
fi
}
function outputCompact {
OUTPUT="%{T$WEATHER_FONT_CODE}%{F$ICON_COLOR}$ICON%{F-}%{T-} $ERR_MSG$COLOR_TEXT_BEGIN$DESCRIPTION$COLOR_TEXT_END"
echo "$OUTPUT"
}
# Weather code description mapping
function getWeatherDescription {
local code=$1
case $code in
0) echo "Clear";;
1) echo "Mainly Clear";;
2) echo "Partly Cloudy";;
3) echo "Overcast";;
45|48) echo "Foggy";;
51) echo "Light Drizzle";;
53) echo "Moderate Drizzle";;
55) echo "Dense Drizzle";;
56|57) echo "Freezing Drizzle";;
61) echo "Slight Rain";;
63) echo "Moderate Rain";;
65) echo "Heavy Rain";;
66|67) echo "Freezing Rain";;
71) echo "Slight Snow";;
73) echo "Moderate Snow";;
75) echo "Heavy Snow";;
77) echo "Snow Grains";;
80) echo "Slight Showers";;
81) echo "Moderate Showers";;
82) echo "Violent Showers";;
85) echo "Slight Snow Showers";;
86) echo "Heavy Snow Showers";;
95) echo "Thunderstorm";;
96) echo "Thunderstorm Light Hail";;
99) echo "Thunderstorm Heavy Hail";;
*) echo "Unknown";;
esac
}
getData $1
if [ $ERROR -eq 0 ]; then
# Parse current weather dari Open-Meteo
TEMP=$(echo $RESPONSE | jq -r '.current.temperature_2m')
WID=$(echo $RESPONSE | jq -r '.current.weather_code')
WINDFORCE_ACTUAL=$(echo $RESPONSE | jq -r '.current.wind_speed_10m')
HUMIDITY=$(echo $RESPONSE | jq -r '.current.relative_humidity_2m')
# Parse sunrise/sunset (dalam format ISO8601)
SUNRISE_ISO=$(echo $RESPONSE | jq -r '.daily.sunrise[0]')
SUNSET_ISO=$(echo $RESPONSE | jq -r '.daily.sunset[0]')
# Convert ISO8601 to unix timestamp
SUNRISE=$(date -d "$SUNRISE_ISO" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M" "$SUNRISE_ISO" +%s 2>/dev/null || echo "0")
SUNSET=$(date -d "$SUNSET_ISO" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M" "$SUNSET_ISO" +%s 2>/dev/null || echo "0")
if [ $DISPLAY_LABEL = "yes" ]; then
DESCRIPTION=$(getWeatherDescription $WID)" "
else
DESCRIPTION=""
fi
WIND=""
setIcons $WID
outputCompact
else
echo " "
fi