Skip to content

Commit da95a47

Browse files
authored
Merge pull request #468 from onlyuuuuu/refactor/465/less-complicated-weather-script-updates
Modified the Weather segment script to be less complicated
2 parents c714f0d + 8b9703b commit da95a47

File tree

2 files changed

+117
-94
lines changed

2 files changed

+117
-94
lines changed

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,9 @@ Some segments have their own requirements. If you enable them in your theme, mak
112112
* **tmux_mem_cpu_load.sh**: [tmux-mem-cpu-load](https://github.com/thewtex/tmux-mem-cpu-load)
113113
* **wan_ip.sh**: `curl`
114114
* **weather.sh**:
115-
* Provider *yrno*: `jq`, `curl`, GNU `grep` with Perl regular expression enabled (FreeBSD specific)
115+
* Provider *yrno*: `jq`, `curl`
116116
* **xkb_layout.sh**: X11, XKB
117117

118-
## FreeBSD specific requirements
119-
Preinstalled `grep` in FreeBSD doesn't support Perl regular expressions. Solution is rather simple -- you need to use `textproc/gnugrep` port instead. You also need to make sure, that it has support for PCRE and is compiled with `--enable-perl-regexp` flag.
120-
121-
122118
# Installation
123119
1. Install [tpm](https://github.com/tmux-plugins/tpm) and make sure it's working.
124120
2. Install tmux-powerline as a plugin by adding a line to `tmux.conf`:

segments/weather.sh

Lines changed: 116 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,64 @@
33
# To configure your location, set TMUX_POWERLINE_SEG_WEATHER_LOCATION in the tmux-powerline config file.
44

55
TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER_DEFAULT="yrno"
6-
TMUX_POWERLINE_SEG_WEATHER_JSON_DEFAULT="jq"
76
TMUX_POWERLINE_SEG_WEATHER_UNIT_DEFAULT="c"
87
TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD_DEFAULT="600"
9-
10-
if shell_is_bsd && [ -f /user/local/bin/grep ]; then
11-
TMUX_POWERLINE_SEG_WEATHER_GREP_DEFAULT="/usr/local/bin/grep"
12-
else
13-
TMUX_POWERLINE_SEG_WEATHER_GREP_DEFAULT="grep"
14-
fi
8+
TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD_DEFAULT="86400" # 24 hours
9+
TMUX_POWERLINE_SEG_WEATHER_LAT_DEFAULT="auto"
10+
TMUX_POWERLINE_SEG_WEATHER_LON_DEFAULT="auto"
1511

1612
generate_segmentrc() {
1713
read -r -d '' rccontents <<EORC
18-
# The data provider to use. Currently only "yahoo" is supported.
14+
# The data provider to use. Currently only "yrno" is supported.
1915
export TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER="${TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER_DEFAULT}"
2016
# What unit to use. Can be any of {c,f,k}.
2117
export TMUX_POWERLINE_SEG_WEATHER_UNIT="${TMUX_POWERLINE_SEG_WEATHER_UNIT_DEFAULT}"
2218
# How often to update the weather in seconds.
2319
export TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD="${TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD_DEFAULT}"
24-
# Name of GNU grep binary if in PATH, or path to it.
25-
export TMUX_POWERLINE_SEG_WEATHER_GREP="${TMUX_POWERLINE_SEG_WEATHER_GREP_DEFAULT}"
26-
# Location of the JSON parser, jq
27-
export TMUX_POWERLINE_SEG_WEATHER_JSON="${TMUX_POWERLINE_SEG_WEATHER_JSON_DEFAULT}"
20+
# How often to update the weather location in seconds (this is only used when latitude and longitude settings are set to "auto")
21+
export TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD="${TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD_DEFAULT}"
2822
# Your location
2923
# Latitude and Longtitude for use with yr.no
30-
# Set both to "auto" to detect automatically based on your IP address
31-
TMUX_POWERLINE_SEG_WEATHER_LAT=""
32-
TMUX_POWERLINE_SEG_WEATHER_LON=""
24+
# Set both to "auto" to detect automatically based on your IP address, or set them manually
25+
export TMUX_POWERLINE_SEG_WEATHER_LAT="${TMUX_POWERLINE_SEG_WEATHER_LAT_DEFAULT}"
26+
export TMUX_POWERLINE_SEG_WEATHER_LON="${TMUX_POWERLINE_SEG_WEATHER_LON_DEFAULT}"
3327
EORC
3428
echo "$rccontents"
3529
}
3630

3731
run_segment() {
38-
__process_settings
39-
local tmp_file="${TMUX_POWERLINE_DIR_TEMPORARY}/temp_weather_file.txt"
40-
local weather
41-
case "$TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER" in
42-
"yrno") weather=$(__yrno) ;;
43-
*)
44-
echo "Unknown weather provider [$TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER]"
45-
return 1
46-
;;
47-
esac
48-
if [ -n "$weather" ]; then
49-
echo "$weather"
32+
local cache_weather_file="${TMUX_POWERLINE_DIR_TEMPORARY}/weather_cache_data.txt"
33+
local cache_location_file="${TMUX_POWERLINE_DIR_TEMPORARY}/weather_cache_location.txt"
34+
local weather=""
35+
36+
# Check if the weather data is still a valid cache hit
37+
if [ -f "$cache_weather_file" ]; then
38+
last_update=$(__read_file_last_update "$cache_weather_file")
39+
time_now=$(date +%s)
40+
up_to_date=$(echo "(${time_now}-${last_update}) < ${TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD}" | bc)
41+
if [ "$up_to_date" -eq 1 ]; then
42+
weather=$(__read_file_content "$cache_weather_file")
43+
fi
5044
fi
45+
46+
# Fetch from provider if empty
47+
# If a new provider is implemented, please set the $weather variable!
48+
if [ -z "$weather" ]; then
49+
__process_settings
50+
case "$TMUX_POWERLINE_SEG_WEATHER_DATA_PROVIDER" in
51+
"yrno")
52+
weather=$(__yrno)
53+
;;
54+
*)
55+
# Just read the stale cache, default to empty/blank
56+
# Better not overwriting the previous healthy content
57+
weather=$(__read_file_content "$cache_weather_file")
58+
;;
59+
esac
60+
echo "$weather" > "$cache_weather_file"
61+
fi
62+
63+
echo "$weather"
5164
}
5265

5366
__process_settings() {
@@ -60,66 +73,52 @@ __process_settings() {
6073
if [ -z "$TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD" ]; then
6174
export TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD="${TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD_DEFAULT}"
6275
fi
63-
if [ -z "$TMUX_POWERLINE_SEG_WEATHER_GREP" ]; then
64-
export TMUX_POWERLINE_SEG_WEATHER_GREP="${TMUX_POWERLINE_SEG_WEATHER_GREP_DEFAULT}"
65-
fi
66-
if [ -z "$TMUX_POWERLINE_SEG_WEATHER_JSON" ]; then
67-
export TMUX_POWERLINE_SEG_WEATHER_JSON="${TMUX_POWERLINE_SEG_WEATHER_JSON_DEFAULT}"
76+
if [ -z "$TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD" ]; then
77+
export TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD="${TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD_DEFAULT}"
6878
fi
69-
if [ "$TMUX_POWERLINE_SEG_WEATHER_LAT" = "auto" ] || [ "$TMUX_POWERLINE_SEG_WEATHER_LON" = "auto" ]; then
79+
if [ "$TMUX_POWERLINE_SEG_WEATHER_LAT" = "auto" ] || [ "$TMUX_POWERLINE_SEG_WEATHER_LON" = "auto" ] || [ -z "$TMUX_POWERLINE_SEG_WEATHER_LON" ] || [ -z "$TMUX_POWERLINE_SEG_WEATHER_LAT" ]; then
7080
if ! get_auto_location; then
7181
exit 8
7282
fi
73-
elif [ -z "$TMUX_POWERLINE_SEG_WEATHER_LON" ] || [ -z "$TMUX_POWERLINE_SEG_WEATHER_LAT" ]; then
74-
echo "No location defined." >&2
75-
exit 8
7683
fi
7784
}
7885

86+
# An implementation of a weather provider, just need to echo the result, run_segment() will take care of the rest
7987
__yrno() {
80-
degree=""
81-
if [ -f "$tmp_file" ]; then
82-
if shell_is_macos || shell_is_bsd; then
83-
last_update=$(stat -f "%m" "${tmp_file}")
84-
elif shell_is_linux; then
85-
last_update=$(stat -c "%Y" "${tmp_file}")
86-
fi
87-
time_now=$(date +%s)
88+
local degree=""
8889

89-
up_to_date=$(echo "(${time_now}-${last_update}) < ${TMUX_POWERLINE_SEG_WEATHER_UPDATE_PERIOD}" | bc)
90-
if [ "$up_to_date" -eq 1 ]; then
91-
__read_tmp_file
90+
# There's a chance that you will get rate limited or both location APIs are not working
91+
# Then long and lat will be "null", as literal string
92+
if [ -z "$TMUX_POWERLINE_SEG_WEATHER_LAT" ] || [ -z "$TMUX_POWERLINE_SEG_WEATHER_LON" ]; then
93+
echo "Err: Unable to auto-detect your location"
94+
return 1
95+
fi
96+
97+
if weather_data=$(curl --max-time 4 -s "https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=${TMUX_POWERLINE_SEG_WEATHER_LAT}&lon=${TMUX_POWERLINE_SEG_WEATHER_LON}"); then
98+
error=$(echo "$weather_data" | grep -i "error")
99+
if [ -n "$error" ]; then
100+
echo "error"
101+
return 1
92102
fi
103+
degree=$(echo "$weather_data" | jq -r '.properties.timeseries | .[0].data.instant.details.air_temperature')
104+
condition=$(echo "$weather_data" | jq -r '.properties.timeseries | .[0].data.next_1_hours.summary.symbol_code')
93105
fi
94106

95107
if [ -z "$degree" ]; then
96-
if weather_data=$(curl --max-time 4 -s "https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=${TMUX_POWERLINE_SEG_WEATHER_LAT}&lon=${TMUX_POWERLINE_SEG_WEATHER_LON}"); then
97-
grep=$TMUX_POWERLINE_SEG_WEATHER_GREP_DEFAULT
98-
error=$(echo "$weather_data" | $grep -i "error")
99-
if [ -n "$error" ]; then
100-
echo "error"
101-
exit 1
102-
fi
103-
104-
jsonparser="${TMUX_POWERLINE_SEG_WEATHER_JSON}"
105-
degree=$(echo "$weather_data" | $jsonparser -r '.properties.timeseries | .[0].data.instant.details.air_temperature')
106-
condition=$(echo "$weather_data" | $jsonparser -r '.properties.timeseries | .[0].data.next_1_hours.summary.symbol_code')
107-
elif [ -f "${tmp_file}" ]; then
108-
__read_tmp_file
109-
fi
108+
echo "yr.no err: unable to fetch weather data"
109+
return 1
110110
fi
111111

112-
if [ -n "$degree" ]; then
113-
if [ "$TMUX_POWERLINE_SEG_WEATHER_UNIT" == "k" ]; then
114-
degree=$(echo "${degree} + 273.15" | bc)
115-
fi
116-
if [ "$TMUX_POWERLINE_SEG_WEATHER_UNIT" == "f" ]; then
117-
degree=$(echo "${degree} * 9 / 5 + 32" | bc)
118-
fi
119-
# condition_symbol=$(__get_yrno_condition_symbol "$condition" "$sunrise" "$sunset")
120-
condition_symbol=$(__get_yrno_condition_symbol "$condition")
121-
echo "${condition_symbol} ${degree}°$(echo "$TMUX_POWERLINE_SEG_WEATHER_UNIT" | tr '[:lower:]' '[:upper:]')" | tee "${tmp_file}"
112+
if [ "$TMUX_POWERLINE_SEG_WEATHER_UNIT" == "k" ]; then
113+
degree=$(echo "${degree} + 273.15" | bc)
122114
fi
115+
if [ "$TMUX_POWERLINE_SEG_WEATHER_UNIT" == "f" ]; then
116+
degree=$(echo "${degree} * 9 / 5 + 32" | bc)
117+
fi
118+
# condition_symbol=$(__get_yrno_condition_symbol "$condition" "$sunrise" "$sunset")
119+
condition_symbol=$(__get_yrno_condition_symbol "$condition")
120+
# Write the <content@date>, separated by a @ character, so we can fetch it later on without having to call 'stat'
121+
echo "${condition_symbol} ${degree}°$(echo "$TMUX_POWERLINE_SEG_WEATHER_UNIT" | tr '[:lower:]' '[:upper:]')@$(date +%s)"
123122
}
124123

125124
# Get symbol for condition. Available symbol names: https://api.met.no/weatherapi/weathericon/2.0/documentation#List_of_symbols
@@ -177,23 +176,43 @@ __get_yrno_condition_symbol() {
177176
esac
178177
}
179178

180-
__read_tmp_file() {
181-
if [ ! -f "$tmp_file" ]; then
179+
__read_file_split() {
180+
file_to_read="$1"
181+
lookup_index="$2"
182+
fallback_value="$3"
183+
if [ ! -f "$file_to_read" ]; then
184+
echo "$fallback_value"
185+
return
186+
fi
187+
local -a file_arr
188+
IFS='@' read -ra file_arr <<< "$(cat "$file_to_read")"
189+
if [ -z "${file_arr[$lookup_index]}" ]; then
190+
echo "$fallback_value"
182191
return
183192
fi
184-
cat "${tmp_file}"
185-
exit
193+
echo "${file_arr[$lookup_index]}"
194+
}
195+
196+
# Default to empty/blank
197+
__read_file_content() {
198+
__read_file_split "$1" 0 ""
199+
}
200+
201+
# Default to 0
202+
__read_file_last_update() {
203+
__read_file_split "$1" 1 0
186204
}
187205

188206
get_auto_location() {
189-
local cache_file="${TMUX_POWERLINE_DIR_TEMPORARY}/weather_location_cache.txt"
190-
local max_cache_age=86400 # 24 hours
207+
local max_cache_age=$TMUX_POWERLINE_SEG_WEATHER_LOCATION_UPDATE_PERIOD
208+
local -a lat_lon_arr
191209

192-
if [[ -f "$cache_file" ]]; then
193-
local cache_age=$(($(date +%s) - $(stat -c %Y "$cache_file" 2>/dev/null || echo 0)))
210+
if [[ -f "$cache_location_file" ]]; then
211+
local cache_age=$(($(date +%s) - $(__read_file_last_update "$cache_location_file")))
194212
if (( cache_age < max_cache_age )); then
195-
TMUX_POWERLINE_SEG_WEATHER_LAT=$(grep -oP "(?<=TMUX_POWERLINE_SEG_WEATHER_LAT=')[^']*" "$cache_file")
196-
TMUX_POWERLINE_SEG_WEATHER_LON=$(grep -oP "(?<=TMUX_POWERLINE_SEG_WEATHER_LON=')[^']*" "$cache_file")
213+
IFS=' ' read -ra lat_lon_arr <<< "$(__read_file_content "$cache_location_file")"
214+
TMUX_POWERLINE_SEG_WEATHER_LAT=${lat_lon_arr[0]}
215+
TMUX_POWERLINE_SEG_WEATHER_LON=${lat_lon_arr[1]}
197216
if [[ -n "$TMUX_POWERLINE_SEG_WEATHER_LAT" && -n "$TMUX_POWERLINE_SEG_WEATHER_LON" ]]; then
198217
return 0
199218
fi
@@ -214,18 +233,26 @@ get_auto_location() {
214233
TMUX_POWERLINE_SEG_WEATHER_LON="${loc[1]}"
215234
;;
216235
esac
217-
if [[ -n "$TMUX_POWERLINE_SEG_WEATHER_LAT" && -n "$TMUX_POWERLINE_SEG_WEATHER_LON" ]]; then
218-
mkdir -p "$(dirname "$cache_file")"
219-
echo "TMUX_POWERLINE_SEG_WEATHER_LAT='$TMUX_POWERLINE_SEG_WEATHER_LAT'" > "$cache_file"
220-
echo "TMUX_POWERLINE_SEG_WEATHER_LON='$TMUX_POWERLINE_SEG_WEATHER_LON'" >> "$cache_file"
221-
return 0
236+
237+
# There's no data, move on to the next API, just don't overwrite the previous location
238+
# Also, there's a case where lat/lon was set to "null" as a string, gotta handle it
239+
if [[ -z "$TMUX_POWERLINE_SEG_WEATHER_LAT" ||
240+
-z "$TMUX_POWERLINE_SEG_WEATHER_LON" ||
241+
"$TMUX_POWERLINE_SEG_WEATHER_LAT" == "null" ||
242+
"$TMUX_POWERLINE_SEG_WEATHER_LON" == "null" ]]; then
243+
continue
222244
fi
245+
246+
echo "$TMUX_POWERLINE_SEG_WEATHER_LAT $TMUX_POWERLINE_SEG_WEATHER_LON@$(date +%s)" > "$cache_location_file"
247+
return 0
223248
fi
224249
done
225-
if [[ -f "$cache_file" ]]; then
250+
251+
if [[ -f "$cache_location_file" ]]; then
226252
echo "Warning: Using stale location data (failed to refresh)" >&2
227-
TMUX_POWERLINE_SEG_WEATHER_LAT=$(grep -oP "(?<=TMUX_POWERLINE_SEG_WEATHER_LAT=')[^']*" "$cache_file")
228-
TMUX_POWERLINE_SEG_WEATHER_LON=$(grep -oP "(?<=TMUX_POWERLINE_SEG_WEATHER_LON=')[^']*" "$cache_file")
253+
IFS=' ' read -ra lat_lon_arr <<< "$(__read_file_content "$cache_location_file")"
254+
TMUX_POWERLINE_SEG_WEATHER_LAT=${lat_lon_arr[0]}
255+
TMUX_POWERLINE_SEG_WEATHER_LON=${lat_lon_arr[1]}
229256
if [[ -n "$TMUX_POWERLINE_SEG_WEATHER_LAT" && -n "$TMUX_POWERLINE_SEG_WEATHER_LON" ]]; then
230257
return 0
231258
fi

0 commit comments

Comments
 (0)