I use the Awesome window manager, which relies on the Lua programming language for its configuration and customization. Here I’ll describe the way I use Lua to have Awesome display some informations provided by the underlying GNU/Linux operating system.
Under GNU/Linux, many informations about the machine and its peripherals,
the system, and the network may be found in the /sys
filesystem.
Every (pseudo-)file in that filesystem contains a specific piece of
information exposed directly by the kernel.
It’s pretty simple to access those informations in Lua with the small
SysEntry class shown below. The key principle to know here is that
the __index
function gets called by Lua whenever one tries to
access a field that does not exist in an object’s metatable (see the section
on metatables and metamethods in Lua reference manual). Here,
I use that function to make Lua fetch a value from a file under
/sys
.
SysEntry = { path = nil; new = function(class, o) o = o or {} setmetatable(o, class) return o end; -- Called when accessing a field __index = function(table, key) local val = nil; -- Read attribute value from the corresponding file in /sys local f = io.open("/sys/" .. table.path .. "/" .. key, "r") if f then val = f:read() f:close() end return val end; }
We instanciate an object of that class by providing its constructor with
the pathname to one of the folders in the /sys
filesystem
(without the heading /sys
). For example, to know whether the
machine is plugged to an AC adapter, we can get a SysEntry object for
the /sys/class/power_supply/AC
folder and check the
online property:
ac_adapter = SysEntry:new({ path = "class/power_supply/AC" }) if ac_adapter.online == "1" then print("Running on mains") else print("Running on battery") end
Similarly we can extract information about the battery, such as its current charge:1
battery = SysEntry:new({ path = "class/power_supply/BAT0" }) capacity = battery.charge_full current = battery.charge_now charge = current * 100 / capacity print(string.format("Charge remaining: %.0f %%", charge))
Other informations I get in my Awesome’s configuration include:
/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
);/sys/class/thermal/thermal_zone0/temp
);/sys/class/backlight/intel_backlight/brightness
, assuming an
Intel graphic chip).Some files under /sys
are writable and may be used both to
set a property instead of getting it. The
brightness file mentionned above is one of those; writing to it
allows to change the screen's brightness.
We can add a new member to the SysEntry class above to allow
writing to /sys
.2 The __newindex
function is similar to __index
, but is called whenever one tries
to assign a value to a non-existing field.
local SysEntry = { ... __newindex = function(table, key, value) -- Write attribute value to the corresponding file in /sys local f = io.open("/sys/" .. table.path .. "/" .. key, "w") if f then f:write(tostring(value)) f:close() end end; }
We can now create a new type of helper object to control the screen’s brightness from within Awesome:
BacklightController = { new = function(class, o) if not class.__index then class.__index = class end o = o or {} setmetatable(o, class) o.sys = SysEntry:new({ path = "class/backlight/intel_backlight" }) o.max = tonumber(o.sys.max_brightness) -- We want to increase or decrease the brightness -- by increments of 1/10 of the maximal brightness o.step = o.max // 10 return o end; increase = function(self) local current = tonumber(self.sys.brightness) -- Do nothing if we are already at the max if current < self.max then -- Compute the new value, capping at max if needed local newvalue = current + self.step if newvalue > self.max then newvalue = self.max end -- Write the new value back to /sys self.sys.brightness = newvalue end end; decrease = function(self) local current = tonumber(self.sys.brightness) -- Do nothing if we are already at 10% or less if current > self.step then local newvalue = current - self.step if newvalue < self.step then newvalue = self.step end self.sys.brightness = newvalue end end; }
We can now instanciate a BacklightController object in Awesome’s
rc.lua
and bind the increase and decrease
methods to, say, the XF86MonBrightnessUp
and
XF86MonBrightnessDown
keys.
Why not simply calling xbacklight instead, which has the
advantage of not requiring to make
/sys/class/backlight/intel_backlight/brightness
writable by a
normal user account? Well, on my system xbacklight is not working,
because the modesetting driver for X.org does not
properly expose the backlight property.
/sys
are only writable by a super-user. It’s up
to you to make the files corresponding to the properties you are interested in
modifying writable by your normal user account.