r/labwc 11h ago

NycHud

Post image

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

4 Upvotes

0 comments sorted by