1
0
Fork 0

feat: migrate to i3blocks and autotiling-rs

This commit is contained in:
Oliver Ladner 2026-03-01 14:11:51 +01:00
commit 487870a473
14 changed files with 512 additions and 7 deletions

View file

@ -0,0 +1,70 @@
# Global stuff
separator=true
separator_block_width=8
[fortune]
markup=pango
command=~/bin/i3blocks/fortune
interval=300
[time]
markup=pango
color=#b1e5c8
background=#2E8B57
command=echo " <b>$(date +'%A, %d %B %R %Z')</b> "
interval=10
[wifi]
markup=pango
command=~/bin/i3blocks/wifi
interval=20
[cputemp]
markup=pango
command=~/bin/i3blocks/cputemp
interval=20
# CPU load
[cpu]
markup=pango
command=~/bin/i3blocks/cpu
interval=3
[mem]
markup=pango
command=~/bin/i3blocks/mem
interval=30
[audio]
markup=pango
command=~/bin/i3blocks/audio
interval=once
signal=1
[mic_mute]
markup=pango
command=~/bin/i3blocks/mic_mute
interval=once
signal=2
# Indoor temperature and humidity
[homeassistant-slow]
markup=pango
command=~/bin/i3blocks/homeassistant-slow
interval=60
# Power draw
[homeassistant-fast]
markup=pango
command=~/bin/i3blocks/homeassistant-fast
interval=10
[archupdate]
markup=pango
command=~/bin/i3blocks/archupdates
interval=28800 # 4h
[weather]
markup=pango
command=~/bin/i3blocks/weather
interval=900

View file

@ -44,7 +44,7 @@ output * bg ~/data/local/wallpaper/anders-jilden-AkUR27wtaxs-unsplash.jpg fill
# You can get the names of your outputs by running: swaymsg -t get_outputs
# BSP-style window tiling
exec_always autotiling
exec_always autotiling-rs
# This will lock your screen after 300 seconds of inactivity, then turn off
# your displays after another 300 seconds, and turn your screens back on when
@ -197,11 +197,12 @@ bindsym ctrl+alt+shift+r mode "RESIZE"
# Volume control with PipeWire
# https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h
# Get the device ID with `wpctl status` or use @DEFAULT_AUDIO_SINK@
bindsym --locked XF86AudioMute exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
# bindsym --release XF86AudioMute exec pkill -USR1 swaybar
# The signal is mapped to a i3block configuration
bindsym --locked XF86AudioMute exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle && pkill -SIGRTMIN+1 i3blocks
# `-l` sets max volume level
bindsym --locked XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02- -l 1.0
bindsym --locked XF86AudioRaiseVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02+ -l 1.0
bindsym --locked XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02- -l 1.0 && pkill -SIGRTMIN+1 i3blocks
bindsym --locked XF86AudioRaiseVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02+ -l 1.0 && pkill -SIGRTMIN+1 i3blocks
# FIXME: https://wiki.archlinux.org/title/MPRIS
# bindsym --locked XF86AudioPause exec wpctl set-mute 48 toggle
@ -212,8 +213,10 @@ bindsym Mod4+Shift+Space exec grimshot --notify save window
# man 5 sway-bar
bar {
position bottom
font "BerkeleyMono Nerd Font Mono Normal Bold 11"
status_command ~/.config/sway/status.sh
# font "BerkeleyMono Nerd Font Mono Normal Bold 10"
font "BerkeleyMono Nerd Font Mono Normal Regular 11"
# status_command ~/.config/sway/status.sh
status_command i3blocks
strip_workspace_name no
strip_workspace_numbers no
colors {

View file

@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# Shared utilities for i3blocks scripts.
# Source this file to get color variables and the icon() helper.
# Colors are available immediately on source — no function call needed.
# Generic
ok_fg="#f0f0f0"
warn1_bg="#facc15"
warn1_fg="#36454f"
warn2_bg="#cc8d22"
warn2_fg="#36454f"
crit_bg="#710f3d"
crit_fg="#c0c8c6"
# Audio
mute_bg="#303030"
mute_fg="#e0e0e0"
# Weather
frost_bg="#5b8dd9"
frost_fg="#f0f0f0"
cold_bg="#7ec8e3"
cold_fg="#1a1a2e"
warm_bg="#facc15"
warm_fg="#36454f"
hot_bg="#cc3300"
hot_fg="#f0f0f0"
# Wrap a glyph in Pango markup for consistent icon sizing and vertical alignment
icon() {
echo "<span size='xx-large' rise='-4096'>$1</span>"
}

View file

@ -0,0 +1,22 @@
#!/usr/bin/env bash
. ~/bin/i3blocks/_utils
# Check if updated Arch packages can be installed
pkgupdate() {
local pkgcount=$(checkupdates | wc -l)
if [[ $pkgcount -ge 1 && $pkgcount -lt 20 ]]; then
local bg=$mute_bg
local fg=$mute_fg
elif [[ $pkgcount -ge 20 ]]; then
local bg=$warn1_bg
local fg=$warn1_fg
fi
local stat="$pkgcount pkg updates"
if [[ -n "$bg" ]]; then
echo -e "<span background=\"$bg\" color=\"$fg\">$stat</span>\n"
fi
}
pkgupdate

53
home/oli/bin/i3blocks/audio Executable file
View file

@ -0,0 +1,53 @@
#!/usr/bin/env bash
#
# Display audio volume/mute status
# Depends on signals in sway config for XF86AudioMute, XF86AudioLowerVolume and
# XF86AudioRaiseVolume
. ~/bin/i3blocks/_utils
# Get default audio sink volume and mute status
audio_volume() {
local wpctl_output
wpctl_output=$(wpctl get-volume @DEFAULT_AUDIO_SINK@)
local volume
volume=$(echo "$wpctl_output" | awk '{print $NF * 100}')
local muted
muted=$(echo "$wpctl_output" | grep -c '\[MUTED\]')
local bg fg icon stat
if [[ "$muted" -ge 1 ]]; then
bg=$mute_bg
fg=$mute_fg
stat="$(printf '%.0f' "$volume")%"
elif [[ $(echo "$volume >= 80" | bc -l) == "1" ]]; then
bg=$crit_bg
fg=$crit_fg
stat="$(printf '%.0f' "$volume")%"
elif [[ $(echo "$volume >= 65" | bc -l) == "1" ]]; then
bg=$warn2_bg
fg=$warn2_fg
stat="$(printf '%.0f' "$volume")%"
elif [[ $(echo "$volume >= 50" | bc -l) == "1" ]]; then
bg=$warn1_bg
fg=$warn1_fg
stat="$(printf '%.0f' "$volume")%"
else
stat="$(printf '%.0f' "$volume")%"
fi
if [[ -n "$bg" ]]; then
echo -e "SND <span background=\"$bg\" color=\"$fg\"> $stat </span>\n"
else
echo -e "SND $stat \n"
fi
}
case "$BLOCK_BUTTON" in
1) wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle ;;
4) wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ --limit 1.0 ;;
5) wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- ;;
esac
audio_volume

70
home/oli/bin/i3blocks/cpu Executable file
View file

@ -0,0 +1,70 @@
#!/usr/bin/env bash
#
# Displays per-core CPU usage as Unicode block characters.
# Uses a temp file to track deltas between intervals.
#
# ▄ = load below 50%
# █ = load at or above 50%
# Colors escalate through warn1 -> warn2 -> crit thresholds.
PREV_FILE="/tmp/i3blocks_cpu_prev"
. ~/bin/i3blocks/_utils
# Read current idle and total ticks for each core from /proc/stat
declare -a cur_idle cur_total
i=0
while IFS=' ' read -r cpu user nice system idle iowait irq softirq rest; do
[[ "$cpu" =~ ^cpu[0-9]+$ ]] || continue
cur_idle[$i]=$((idle + iowait))
cur_total[$i]=$((user + nice + system + idle + iowait + irq + softirq))
((i++))
done < /proc/stat
num_cores=$i
# Load previous snapshot if available
declare -a prev_idle prev_total
if [[ -f "$PREV_FILE" ]]; then
i=0
while IFS=' ' read -r p_idle p_total; do
prev_idle[$i]=$p_idle
prev_total[$i]=$p_total
((i++))
done < "$PREV_FILE"
fi
# Save current snapshot for next run
for ((i=0; i<num_cores; i++)); do
echo "${cur_idle[$i]} ${cur_total[$i]}"
done > "$PREV_FILE"
# Build output — one block character per core
output=""
for ((i=0; i<num_cores; i++)); do
delta_total=$(( cur_total[i] - ${prev_total[$i]:-0} ))
delta_idle=$(( cur_idle[i] - ${prev_idle[$i]:-0} ))
if [[ $delta_total -eq 0 ]]; then
pct=0
else
pct=$(( (delta_total - delta_idle) * 100 / delta_total ))
fi
color=""
if [[ $pct -ge 50 ]]; then
color=$crit_bg
char="█"
elif [[ $pct -ge 15 ]]; then
color=$warn1_bg
char="▄"
else
char="_"
fi
if [[ -n "$color" ]]; then
output+="<span color=\"${color}\">${char}</span>"
else
output+="${char}"
fi
done
echo -e "CPU $output\n"

27
home/oli/bin/i3blocks/cputemp Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env bash
. ~/bin/i3blocks/_utils
# Get CPU temperature
temp_cpu() {
local cpu=$(expr $(cat /sys/class/thermal/thermal_zone1/temp) / 1000)
if [[ $(echo "$cpu >= 60" | bc -l ) == "1" ]] && [[ $(echo "$cpu < 70" | bc -l ) == "1" ]]; then
local bg=$warn1_bg
local fg=$warn1_fg
elif [[ $(echo "$cpu >= 70" | bc -l ) == "1" ]] && [[ $(echo "$cpu < 80" | bc -l ) == "1" ]]; then
local bg=$warn2_bg
local fg=$warn2_fg
elif [[ $(echo "$cpu >= 80" | bc -l ) == "1" ]]; then
local bg=$crit_bg
local fg=$crit_fg
fi
local stat="CPU $cpu°C"
if [[ -n "$bg" ]]; then
echo -e "<span background=\"$bg\" color=\"$fg\">$stat</span>\n"
else
echo -e "$stat\n"
fi
}
temp_cpu

2
home/oli/bin/i3blocks/fortune Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
echo -e "$(fortune -s -n 60 | sed 's/^[[:space:]]*//' | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g' | sed 's/[[:space:]]*$//')\n"

View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
#
# Needs a .env.homeassistant with an API token in ~/.config/sway/.env.homeassistant
# TODO:
# - HA optimize API calls: https://community.home-assistant.io/t/get-limited-number-of-states-entities-when-using-api-states/830323
homeassistant_url="http://10.7.1.11:8123/api/states"
. ~/.config/sway/.env.homeassistant
. ~/bin/i3blocks/_utils
ha() {
local power=$(curl -s -H "Authorization: Bearer $ha_token" -H "Content-Type: application/json" $homeassistant_url/sensor.inspelning_oli_power | jq -r '.state')
local stat="PWR ${power}W"
echo "$stat"
}
ha

View file

@ -0,0 +1,19 @@
#!/usr/bin/env bash
#
# Needs a .env.homeassistant with an API token in ~/.config/sway/.env.homeassistant
# TODO:
# - HA optimize API calls: https://community.home-assistant.io/t/get-limited-number-of-states-entities-when-using-api-states/830323
homeassistant_url="http://10.7.1.11:8123/api/states"
. ~/.config/sway/.env.homeassistant
. ~/bin/i3blocks/_utils
ha() {
local temp_indoor=$(curl -s -H "Authorization: Bearer $ha_token" -H "Content-Type: application/json" $homeassistant_url/sensor.vindstyrka_oli_temperature | jq -r '.state')
local humidity_indoor=$(curl -s -H "Authorization: Bearer $ha_token" -H "Content-Type: application/json" $homeassistant_url/sensor.vindstyrka_oli_humidity | jq -r '.state')
local stat="IN ${temp_indoor}°C ${humidity_indoor}%"
echo $stat
}
ha

28
home/oli/bin/i3blocks/mem Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
. ~/bin/i3blocks/_utils
# Get total memory usage and show highest consumer
mem(){
local memused=$(free | grep Mem | awk '{printf "%.0f\n", $3/$2 * 100.0}')
local memproc=$(basename "$(ps --no-headers -A --sort -rss -o cmd | head -1 | awk {'print $1'})")
if [[ $(echo "$memused >= 50" | bc -l ) == "1" ]] && [[ $(echo "$memused < 60" | bc -l ) == "1" ]]; then
local bg=$warn1_bg
local fg=$warn1_fg
elif [[ $(echo "$memused >= 60" | bc -l ) == "1" ]] && [[ $(echo "$memused < 70" | bc -l ) == "1" ]]; then
local bg=$warn2_bg
local fg=$warn2_fg
elif [[ $(echo "$memused >= 70" | bc -l ) == "1" ]]; then
local bg=$crit_bg
local fg=$crit_fg
fi
local stat="MEM ${memused}% [$memproc]"
if [[ -n "$bg" ]]; then
echo -e " <span background=\"$bg\" color=\"$fg\"> $stat </span> \n"
else
echo -e "$stat\n"
fi
}
mem

33
home/oli/bin/i3blocks/mic_mute Executable file
View file

@ -0,0 +1,33 @@
#!/usr/bin/env bash
#
# Shows microphone mute status for the default audio source.
# Left click toggles mute.
. ~/bin/i3blocks/_utils
mic_mute() {
if [[ "$BLOCK_BUTTON" == "1" ]]; then
wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
fi
local wpctl_output
wpctl_output=$(wpctl get-volume @DEFAULT_AUDIO_SOURCE@)
local muted
muted=$(echo "$wpctl_output" | grep -c '\[MUTED\]')
local bg fg icon stat
if [[ "$muted" -ge 1 ]]; then
bg=$mute_bg
fg=$mute_fg
stat="MUT"
else
bg=$crit_bg
fg=$crit_fg
stat="REC"
fi
echo -e "MIC <span background=\"$bg\" color=\"$fg\"> $stat </span>\n"
}
mic_mute

99
home/oli/bin/i3blocks/weather Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env bash
#
# Fetches current weather for Herzogenbuchsee, Switzerland via open-meteo.com.
# No API key required.
#
# WMO weather codes: https://open-meteo.com/en/docs#weathervariables
# Coordinates for Herzogenbuchsee, CH
LAT="47.1897"
LON="7.7058"
# NOTE: MeteoSwiss ICON-CH1 model (~1 km resolution) via open-meteo, matching
# the MeteoSwiss mobile app data source.
API_URL="https://api.open-meteo.com/v1/forecast"
MODEL="meteoswiss_icon_ch1"
. ~/bin/i3blocks/_utils
# Map WMO weather interpretation codes to icons (Nerd Font nf-weather-*)
wmo_icon() {
local code=$1
case $code in
0) echo "clear" ;; # Clear sky
1) echo "mostly clear" ;; # Mainly clear
2) echo "partly cloudy" ;; # Partly cloudy
3) echo "overcast" ;; # Overcast
45|48) echo "fog" ;; # Fog / depositing rime fog
51|53|55) echo "drizzle" ;; # Drizzle: light, moderate, dense
56|57) echo "freezing drizzle" ;; # Freezing drizzle: light, dense
61|63|65) echo "rain" ;; # Rain: slight, moderate, heavy
66|67) echo "freezing rain" ;; # Freezing rain: light, heavy
71|73|75|77) echo "snow" ;; # Snow: slight, moderate, heavy, snow grains
80|81|82) echo "showers" ;; # Rain showers: slight, moderate, violent
85|86) echo "snow showers" ;; # Snow showers: slight, heavy
95) echo "thunderstorm" ;; # Thunderstorm
96|99) echo "thunderstorm+hail" ;; # Thunderstorm with hail: slight, heavy
*) echo "?" ;;
esac
}
weather() {
local response
response=$(curl -sf "${API_URL}?latitude=${LAT}&longitude=${LON}&current=temperature_2m,apparent_temperature,weather_code,wind_speed_10m&daily=sunrise,sunset&wind_speed_unit=kmh&timezone=Europe%2FZurich&models=${MODEL}")
if [[ $? -ne 0 || -z "$response" ]]; then
echo " N/A"
exit 0
fi
local temp apparent code wind sunrise sunset
temp=$(echo "$response" | jq -r '.current.temperature_2m')
apparent=$(echo "$response" | jq -r '.current.apparent_temperature')
code=$(echo "$response" | jq -r '.current.weather_code')
wind=$(echo "$response" | jq -r '.current.wind_speed_10m')
sunrise=$(echo "$response" | jq -r '.daily.sunrise[0]')
sunset=$(echo "$response" | jq -r '.daily.sunset[0]')
# Compare current time against sunrise/sunset (format: YYYY-MM-DDTHH:MM)
local now sunrise_epoch sun_label sun_time
now=$(date +%s)
sunrise_epoch=$(date -d "$sunrise" +%s)
if [[ $now -lt $sunrise_epoch ]]; then
sun_label=""
sun_time=$(date -d "$sunrise" +%H:%M)
else
sun_label=""
sun_time=$(date -d "$sunset" +%H:%M)
fi
local label
label=$(wmo_icon "$code")
local bg fg stat
if [[ $(echo "$temp < 0" | bc -l) == "1" ]]; then
bg=$frost_bg
fg=$frost_fg
elif [[ $(echo "$temp < 8" | bc -l) == "1" ]]; then
bg=$cold_bg
fg=$cold_fg
elif [[ $(echo "$temp >= 28" | bc -l) == "1" ]]; then
bg=$hot_bg
fg=$hot_fg
elif [[ $(echo "$temp >= 22" | bc -l) == "1" ]]; then
bg=$warm_bg
fg=$warm_fg
fi
# NOTE: apparent temperature shown in parentheses as "feels like"
stat="$label $(printf '%.0f' "$temp")°C ($(printf '%.0f' "$apparent")°C) $(printf '%.0f' "$wind") km/h $sun_label $sun_time"
if [[ -n "$bg" ]]; then
echo -e "OUT <span background="$bg" color="$fg"> $stat </span> "
else
echo -e "OUT $stat "
fi
}
weather

28
home/oli/bin/i3blocks/wifi Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
. ~/bin/i3blocks/_utils
# Get WiFi signal strength
wifi() {
local wifidbm_orig=$(iwctl station wlan0 show | awk '/[[:space:]]RSSI/{print $2}')
local wifidbm=$((wifidbm_orig * -1))
if [[ $(echo "$wifidbm >= 50" | bc -l ) == "1" ]] && [[ $(echo "$wifidbm < 60" | bc -l ) == "1" ]]; then
local bg=$warn1_bg
local fg=$warn1_fg
elif [[ $(echo "$wifidbm >= 60" | bc -l ) == "1" ]] && [[ $(echo "$wifidbm < 70" | bc -l ) == "1" ]]; then
local bg=$warn2_bg
local fg=$warn2_fg
elif [[ $(echo "$wifidbm >= 70" | bc -l ) == "1" ]]; then
local bg=$crit_bg
local fg=$crit_fg
fi
local stat="NET -${wifidbm} dBm"
if [[ -n "$bg" ]]; then
echo -e "<span background=\"$bg\" color=\"$fg\">$stat</span>\n"
else
echo -e "$stat\n"
fi
}
wifi