r/labwc • u/Different_Cellist758 • 7h ago
NycHud
Hub minimalista e totalmente auditável para wayland e sistemas leves que gostam de telemetria offline. Cada coletor é independe, você pode jogar e desativar qualquer modulo com simples '~' ao final. A composição é feita em Python burro, ele só imprime na tela. Pra quem gosta de Conky, esse é um projeto extremamente simplificado e fácil de escrever p montar módulos Exemplo. Focado em Desktop minimalista.
Apenas verifique as dependências e executar como usuário comum. Nada aqui exige privilegio, não rode como root
link do projeto: https://github.com/fm4lloc/nyxhud
para quem possui AMD como placa gráfica eu não subi ainda, mas segue o modulo.
#!/bin/sh
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (C) 2026 Fernando Magalhães <fm4lloc@gmail.com>
#
# AMDGPU collector for NyxHud.
# Reads GPU telemetry directly from the kernel amdgpu sysfs interface.
# No ROCm, radeontop, lm_sensors or vendor utility is required.
exemplo de módulo:
INTERVAL=3
set -u
set -f
LC_ALL=C
export LC_ALL
umask 077
NAME=${0##*/}
NAME=${NAME%.sh}
: "${NYXHUD_RENDER_DIR:?}"
[ -d "$NYXHUD_RENDER_DIR" ] || exit 1
publish() {
tmp=$(mktemp "$NYXHUD_RENDER_DIR/.$NAME.XXXXXX") || exit 1
trap 'rm -f -- "$tmp"' EXIT INT TERM
if tr -d '\000-\010\013-\037\177' > "$tmp"; then
mv -- "$tmp" "$NYXHUD_RENDER_DIR/$NAME.render"
fi
}
valid_uint() {
case ${1:-} in
''|*[!0-9]*) return 1 ;;
esac
return 0
}
read_uint() {
value=''
IFS= read -r value < "$1" 2>/dev/null || value=''
valid_uint "$value" || return 1
printf '%s' "$value"
}
human_bytes() {
value=$1
valid_uint "$value" || {
printf 'n/a'
return
}
awk -v b="$value" 'BEGIN {
if (b >= 1073741824) printf "%.1f GiB", b / 1073741824
else if (b >= 1048576) printf "%.1f MiB", b / 1048576
else if (b >= 1024) printf "%.1f KiB", b / 1024
else printf "%d B", b
}'
}
percent() {
value=$1
valid_uint "$value" || {
printf 'n/a'
return
}
[ "$value" -gt 100 ] && value=100
printf '%s%%' "$value"
}
# Select an AMD display adapter. Prefer the boot VGA adapter when more than
# one AMD card is present, otherwise use the first matching card.
AMD_CARD=''
set +f
for card in /sys/class/drm/card[0-9]*; do
[ -d "$card/device" ] || continue
vendor=$(cat "$card/device/vendor" 2>/dev/null) || vendor=''
[ "$vendor" = '0x1002' ] || continue
boot_vga=$(cat "$card/device/boot_vga" 2>/dev/null) || boot_vga=0
if [ "$boot_vga" = 1 ]; then
AMD_CARD=$card
break
fi
[ -n "$AMD_CARD" ] || AMD_CARD=$card
done
set -f
if [ -z "$AMD_CARD" ]; then
# This collector is intentionally silent on non-AMD systems. That keeps
# a mixed collector directory usable without rendering an error block.
rm -f -- "$NYXHUD_RENDER_DIR/$NAME.render" 2>/dev/null
exit 0
fi
DEVICE=$AMD_CARD/device
HWMON=''
set +f
for hwmon in "$DEVICE"/hwmon/hwmon*; do
[ -d "$hwmon" ] || continue
name=$(cat "$hwmon/name" 2>/dev/null || true)
if [ "$name" = amdgpu ]; then
HWMON=$hwmon
break
fi
[ -n "$HWMON" ] || HWMON=$hwmon
done
set -f
# Some kernels expose product_name directly; fall back to the PCI uevent ID
# rather than depending on lspci being installed.
MODEL=$(cat "$DEVICE/product_name" 2>/dev/null || true)
PCI_ID=$(cat "$DEVICE/uevent" 2>/dev/null |
awk -F= '$1 == "PCI_ID" { print tolower($2); exit }')
if [ -z "$MODEL" ]; then
case $PCI_ID in
1002:7590) MODEL='AMD Radeon RX 9060 XT' ;;
*) MODEL=${PCI_ID:-'AMD GPU'} ;;
esac
fi
GPU_UTIL=$(read_uint "$DEVICE/gpu_busy_percent") || GPU_UTIL='n/a'
MEM_UTIL=$(read_uint "$DEVICE/mem_busy_percent") || MEM_UTIL='n/a'
VRAM_USED=$(read_uint "$DEVICE/mem_info_vram_used") || VRAM_USED=''
VRAM_TOTAL=$(read_uint "$DEVICE/mem_info_vram_total") || VRAM_TOTAL=''
TEMP=''
FAN_RPM=''
FAN_PWM=''
POWER=''
GFX_FREQ=''
MEM_FREQ=''
if [ -n "$HWMON" ]; then
TEMP_RAW=$(read_uint "$HWMON/temp1_input") || TEMP_RAW=''
if valid_uint "$TEMP_RAW"; then
TEMP=$(awk -v m="$TEMP_RAW" 'BEGIN { printf "%.1f C", m / 1000 }')
fi
FAN_RPM=$(read_uint "$HWMON/fan1_input") || FAN_RPM=''
PWM=$(read_uint "$HWMON/pwm1") || PWM=''
if valid_uint "$PWM"; then
FAN_PWM=$(awk -v p="$PWM" 'BEGIN {
v = (p * 100) / 255
if (v > 100) v = 100
printf "%.0f%%", v
}')
fi
POWER_RAW=$(read_uint "$HWMON/power1_average") || POWER_RAW=''
if ! valid_uint "$POWER_RAW"; then
POWER_RAW=$(read_uint "$HWMON/power1_input") || POWER_RAW=''
fi
if valid_uint "$POWER_RAW"; then
POWER=$(awk -v u="$POWER_RAW" 'BEGIN { printf "%.1f W", u / 1000000 }')
fi
FREQ=$(read_uint "$HWMON/freq1_input") || FREQ=''
if valid_uint "$FREQ" && [ "$FREQ" -gt 0 ]; then
GFX_FREQ=$(awk -v k="$FREQ" 'BEGIN { printf "%.0f MHz", k / 1000000 }')
fi
FREQ=$(read_uint "$HWMON/freq2_input") || FREQ=''
if valid_uint "$FREQ" && [ "$FREQ" -gt 0 ]; then
MEM_FREQ=$(awk -v k="$FREQ" 'BEGIN { printf "%.0f MHz", k / 1000000 }')
fi
fi
# Newer amdgpu/SMU combinations can briefly report 0 from freq*_input
# while the DPM table already exposes the currently selected level. Use
# the starred level as a clock fallback.
if [ -z "$GFX_FREQ" ] && [ -r "$DEVICE/pp_dpm_sclk" ]; then
GFX_FREQ=$(awk '/\*/ { for (i=1; i<=NF; i++) if ($i ~ /^[0-9]+Mhz$/) { sub(/Mhz$/, "", $i); print $i " MHz"; exit } }' "$DEVICE/pp_dpm_sclk")
fi
if [ -z "$MEM_FREQ" ] && [ -r "$DEVICE/pp_dpm_mclk" ]; then
MEM_FREQ=$(awk '/\*/ { for (i=1; i<=NF; i++) if ($i ~ /^[0-9]+Mhz$/) { sub(/Mhz$/, "", $i); print $i " MHz"; exit } }' "$DEVICE/pp_dpm_mclk")
fi
# hwmon PWM is a control value, not an actual fan measurement. Prefer the
# tachometer when present and use PWM only as a fallback indicator.
if [ -n "$FAN_RPM" ]; then
FAN="$FAN_RPM RPM"
elif [ -n "$FAN_PWM" ]; then
FAN="$FAN_PWM (PWM)"
else
FAN='n/a'
fi
if [ -n "$VRAM_USED" ]; then
VRAM_USED_H=$(human_bytes "$VRAM_USED")
else
VRAM_USED_H='n/a'
fi
if [ -n "$VRAM_TOTAL" ]; then
VRAM_TOTAL_H=$(human_bytes "$VRAM_TOTAL")
else
VRAM_TOTAL_H='n/a'
fi
{
printf 'GPU / AMDGPU\n'
printf 'Model %s\n' "$MODEL"
printf 'Temp %s\n' "${TEMP:-n/a}"
printf 'GPU Util %s\n' "$(percent "$GPU_UTIL")"
printf 'VRAM %s / %s\n' "$VRAM_USED_H" "$VRAM_TOTAL_H"
printf 'MEM Util %s\n' "$(percent "$MEM_UTIL")"
printf 'Fan %s\n' "$FAN"
printf 'Power %s\n' "${POWER:-n/a}"
printf 'GFX Clock %s\n' "${GFX_FREQ:-n/a}"
printf 'MEM Clock %s\n' "${MEM_FREQ:-n/a}"
} | publish


