awful.widget.watch use case examples

bitcoin

Requires curl and dkjson or lain.

local bitcoin = awful.widget.watch(
    "curl -m5 -s 'https://coinbase.com/api/v1/prices/buy'",
    43200, -- half day
    function(widget, stdout)
        local btc, pos, err = require("dkjson").decode(stdout, 1, nil) -- dkjson
        --local btc, pos, err = require("lain.util").dkjson.decode(stdout, 1, nil) -- lain
        local btc_price = (not err and btc and btc["subtotal"]["amount"]) or "N/A"

        -- customize here
        widget:set_text(btc_price)
    end
)

brtfs

-- btrfs root df
local myrootfs = awful.widget.watch(
    "btrfs filesystem df -g /",
    600, -- 10 minutes
    function(widget, stdout)
        local total, used  = string.match(stdout, "Data.-total=(%d+%.%d+)GiB.-used=(%d+%.%d+)GiB")
        local percent_used = math.ceil((tonumber(used) / tonumber(total)) * 100)

        -- customize here
        widget:set_text(" [/: " .. percent_used .. "%] ")
    end
)

cmus

-- cmus audio player
local cmus, cmus_timer = awful.widget.watch(
    "cmus-remote -Q",
    2,
    function(widget, stdout)
        local cmus_now = {
            state   = "N/A",
            artist  = "N/A",
            title   = "N/A",
            album   = "N/A"
        }

        for w in string.gmatch(stdout, "(.-)tag") do
            a, b = w:match("(%w+) (.-)\n")
            cmus_now[a] = b
        end

        -- customize here
        widget:set_text(cmus_now.artist .. " - " .. cmus_now.title)
    end
)

iostat

-- disk I/O using iostat from sysstat utilities
local iotable = {}
local iostat = awful.widget.watch("iostat -dk", 2, -- in Kb, use -dm for Mb
    function(widget, stdout)
        for line in stdout:match("(sd.*)\n"):gmatch("(.-)\n") do
            local device, tps, read_s, wrtn_s, read, wrtn =
            line:match("(%w+)%s*(%d+,?%d*)%s*(%d+,?%d*)%s*(%d+,?%d*)%s*(%d+,?%d*)%s*(%d+,?%d*)")
            --                  [1]  [2]     [3]     [4]   [5]
            iotable[device] = { tps, read_s, wrtn_s, read, wrtn }
        end

        -- customize here
        widget:set_text("sda: "..iotable["sda"][2].."/"..iotable["sda"][3]) -- read_s/wrtn_s
    end
)

maildir

-- checks whether there are files in the "new" directories of a mail dirtree
local mailpath = "~/Mail"
local mymaildir = awful.widget.watch(
    { awful.util.shell, "-c", string.format("ls -1dr %s/*/new/*", mailpath) },
    60,
    function(widget, stdout)
        local inbox_now = { digest = "" }

        for dir in stdout:gmatch(".-/(%w+)/new") do
            inbox_now[dir] = 1
            for _ in stdout:gmatch(dir) do
                inbox_now[dir] = inbox_now[dir] + 1
            end
            if #inbox_now.digest > 0 then inbox_now.digest = inbox_now.digest .. ", " end
            inbox_now.digest = inbox_now.digest .. string.format("%s (%d)", dir, inbox_now[dir])
        end

        -- customize here
        widget:set_text("mail: " .. inbox_now.digest)
    end
)

mpris

-- infos from mpris clients such as spotify and VLC
-- based on https://github.com/acrisci/playerctl
local mpris, mpris_timer = awful.widget.watch(
    { awful.util.shell, "-c", "playerctl status && playerctl metadata" },
    2,
    function(widget, stdout)
         local escape_f  = require("awful.util").escape
         local mpris_now = {
             state        = "N/A",
             artist       = "N/A",
             title        = "N/A",
             art_url      = "N/A",
             album        = "N/A",
             album_artist = "N/A"
         }

         mpris_now.state = string.match(stdout, "Playing") or
                           string.match(stdout, "Paused")  or "N/A"

         for k, v in string.gmatch(stdout, "'[^:]+:([^']+)':[%s]<%[?'([^']+)'%]?>")
         do
             if     k == "artUrl"      then mpris_now.art_url      = v
             elseif k == "artist"      then mpris_now.artist       = escape_f(v)
             elseif k == "title"       then mpris_now.title        = escape_f(v)
             elseif k == "album"       then mpris_now.album        = escape_f(v)
             elseif k == "albumArtist" then mpris_now.album_artist = escape_f(v)
             end
         end

        -- customize here
        widget:set_text(mpris_now.artist .. " - " .. mpris_now.title)
    end
)

pipewire

-- pactl based volume widget for pure pipewire setups
local volume = awful.widget.watch(
    "pactl get-sink-volume @DEFAULT_SINK@ | cut -s -d/ -f2,4; pactl get-sink-mute @DEFAULT_SINK@",
    5, -- timeout 
    function(widget, stdout)
        local volume = "Volume: "
        for v in stdout:gmatch("(%d+%%)") do volume = volume .. " " .. v end
        if #volume == 8 then volume = "N/A" end
        local mute = string.match(stdout, "Mute: (%S+)") or "N/A"

        -- customize here
        widget:set_markup(volume .. " " .. mute)
    end
)

upower

-- battery infos from freedesktop upower
local mybattery = awful.widget.watch(
    { awful.util.shell, "-c", "upower -i /org/freedesktop/UPower/devices/battery_BAT | sed -n '/present/,/icon-name/p'" },
    30,
    function(widget, stdout)
        local bat_now = {
            present      = "N/A",
            state        = "N/A",
            warninglevel = "N/A",
            energy       = "N/A",
            energyfull   = "N/A",
            energyrate   = "N/A",
            voltage      = "N/A",
            percentage   = "N/A",
            capacity     = "N/A",
            icon         = "N/A"
        }

        for k, v in string.gmatch(stdout, '([%a]+[%a|-]+):%s*([%a|%d]+[,|%a|%d]-)') do
            if     k == "present"       then bat_now.present      = v
            elseif k == "state"         then bat_now.state        = v
            elseif k == "warning-level" then bat_now.warninglevel = v
            elseif k == "energy"        then bat_now.energy       = string.gsub(v, ",", ".") -- Wh
            elseif k == "energy-full"   then bat_now.energyfull   = string.gsub(v, ",", ".") -- Wh
            elseif k == "energy-rate"   then bat_now.energyrate   = string.gsub(v, ",", ".") -- W
            elseif k == "voltage"       then bat_now.voltage      = string.gsub(v, ",", ".") -- V
            elseif k == "percentage"    then bat_now.percentage   = tonumber(v)              -- %
            elseif k == "capacity"      then bat_now.capacity     = string.gsub(v, ",", ".") -- %
            elseif k == "icon-name"     then bat_now.icon         = v
            end
        end

        -- customize here
        widget:set_text("Bat: " .. bat_now.percentage .. " " .. bat_now.state)
    end
)