Sysfs to control GPIO depracted -> Alternatives?

Hi all,
For many years I have been using sysfs to control and monitor my GPIOs.
I usually use something like:

if [ “$(</sys/class/gpio/gpio”${PIR_PIN}“/value)” == “1” ]; then
some commands

Unfortunately, this no longer works because it has been depracted and I have to change. Only to what?
Wiringpi is also depracted, so i wanted to switch to “raspi-gpio”, but then you have to use something like this:

if [ `raspi-gpio get ${PIR_PIN}|awk '{print $3}'|grep -o '.\{1\}$'` = “0” ]; then
some command

Ugly, but it works (Hint: awk and grep is needed to get only 0 or 1 as output).
The problem is that “raspi-gpio” is also depracted and replaced by “pinctrl”. However, this cannot be installed via apt. I ask me why.
Do you have any suggestions on how I can control/monitor the GPIO in bash scripts in the future?
Is there a better way to only get 0/1 from raspi-gpio or another solution that has a future?
Or maybe re enable sysfs?

What about this?

It includes 6 CLI tools which you can use in bash scripts

There are currently six command-line tools available:

* gpiodetect - list all gpiochips present on the system, their names, labels
               and number of GPIO lines

* gpioinfo   - list lines, their gpiochip, offset, name, and direction, and
               if in use then the consumer name and any other configured
               attributes, such as active state, bias, drive, edge detection
               and debounce period

* gpioget    - read values of specified GPIO lines

* gpioset    - set values of specified GPIO lines, holding the lines until the
               process is killed or otherwise exits

* gpiomon    - wait for edge events on GPIO lines, specify which edges to watch
               for, how many events to process before exiting, or if the events
               should be reported to the console

* gpionotify - wait for changed to the info for GPIO lines, specify which
               changes to watch for, how many events to process before exiting,
               or if the events should be reported to the console
1 Like

Thank you very much for answering. Looks very promising!
I have read the documentation but do not understand how to configure a GPIO as input or output. :thinking:
The pin is now an output, but i don’t know how to set it back to input.

probably with gpioset?

I was in contact with a dev from de libgpiod and he told me that it is not possible what i need. :pensive:
So i switched to raspi-gpio. And i compiled pinctrl to see how it works. Would be cool if it find the way in the official repository.
A little bit frustrating. Sysfs, wiringpi and raspi-gpio are depracted and libgpiod is not fully working. And because of that i have to rewrite all of mi scripts :see_no_evil:

I was not aware that the GPIO sysfs does not exist anymore on RPi as well? Makes sense since in mainline kernel is is hidden behind an optional kernel build flag + an additionally required “expert” flag. We just patched it again into our 64-bit Allwinner SoC kernel builds: sunxi64: re-enable GPIO sysfs API · MichaIng/build@cafc178 · GitHub

Yeah, libgpio is quite some downsides. Also that low/high states cannot be changed persistently, but the remain only while gpioset runs, and are reset afterwards: Radxa Zero | SSH Crash "Broken Pipe" after exporting UART TX GPIO pin · Issue #6354 · MichaIng/DietPi · GitHub

Not sure about all those design decisions, and I am not doing enough with GPIO myself to have a qualified opinion, but at least it is often a reason why people are still using the deprecated APIs/libraries, where possible.

I noticed a few days ago that the scripts on the Pi4 are no longer running. And then I noticed that sysfs no longer exists. I think ATM sysfs is only gone on Pi4. Because i have about 18 Pi’s (Zero, 3B, 3B+, 4B), all running dietpi, but only the Pi4 does not support sysfs. The problem is that only one of this 18 is a Pi4. And i am sure it was gone with an update. I think the kernel was updated some time ago and then sysfs was gone.

The problem is that i don’t speak python, because of that i write all of my scripts in bash. :see_no_evil:
I use it very often in combination with OliveTin and GPIOs. With sensors and relais you can control nearby everything. I have already thought about publishing a few of my scripts. Maybe someone else could use it. And since everything is in bash you can understand it “relatively” well.

ATM i think the best way is to use “raspi-gpio” or “pinctrl”. I open a ticket, maybe it is possible to implement a option to only show “0” or “1” for script fans like me. :nerd_face:

Off topic:
Webinterface (OliveTin) to control my garage. It controls the alarmsystem, the gate and the dog. :grin:


Why does:

if [ "$(gpioget --chip 0 31)" == '"31"=active' ] ; then
  echo execute some commands

not work for you?

Have not tried this, but normally you need to configure the GPIO first an then read it out or pull it up/down. In some cases i need inputs (sensors, switches) and in other cases i need outputs (relais, led).

In the meantime “pelwell” implemented an option to “pinctrl” which gives 0/1 back. So now all i have done before with sysfs is doable with pinctrl. :star_struck:

1 Like

This is the world of libgpiod, not deprecated sysfs, it’s much smarter than you think.
But who am I telling that, keep using your legacy stuff and keep fighting to keep ist alive.
At least it saves you updates, because there probably won’t be anything new in mainline in this direction.
But you should be aware that the depricated sysfs interface has been just a wrapper around gpiochip for years and thus the statement: “libgpiod can do less than sysfs” is technically not possible.

1 Like

I actually never heard of pinctrl (CLI tool) so far. Part of raspi-utils, right? What is the particular benefit over gpiod tools? RPi Ltd. moved to generic tools and open standards in so many cases, but here they maintain a new RPi-only tool?

GPIO sysfs may be deprecated, and there will be reasons for this I do not know/remember, but it has many benefts to be able to I/O just via file system interface: No external executables required, no libraries, no special language bindings, no learning of syntax/methods/CLI, just simple via universal file I/O. For the same reason I am not exactly a fan of libcamera, respectively new RPi camera modules requiring it instead of having the option to just get an MJPEG stream right from /dev/video0.

@usual-user: Uhhh, what’s wrong with you? :thinking: Calm down…

@MichaIng: Yes this is exactly the point. It was so “easy” to just use sysfs. And this is also why i always try to use bash. It works always on nearby every linux system. If you have python, php, java or similar it can be that your tool is not running anymore if they switch from php2 to php3 (see motioneye for example). Same thing with php (see nextcloud).
Yes pinctrl seems to be part of raspi-utils. I don’t know what’s the benefit of it. I just searching a “new” way to control GPIOs and stumbled over it. I have used raspi-gpio before because sysfs could not set pull resistors. So i knew it and know how it works. The only thing was that it was not possible to get 0/1, but this is fixed now. So i can use this in the future. :ok_hand:
Hope it will find the way in the official repository and will replace raspi-gpio in the future.
If someone knows the pros or cons from “pinctrl vs. gpiod” let mi know.

I mean, if you only need to check the value, and do not need the integer itself for some math, otherwise formatted output or such, then indeed what @usual-user user suggested will just work the very same way, regardless which tool you use and how simple or complex the output is. But I agree that a clean value-only output is nicer, at last more flexible and simpler to further handle, when required.


if [ `raspi-gpio get ${PIR_PIN}|awk '{print $3}'|grep -o '.\{1\}$'` = "0" ]; then

in your OP however indeed does not make sense, as you can just match the full line, instead of scraping and matching the 0 :wink:.

I don’t think so. The output from “raspi-gpio get 12” is:
GPIO 12: level=1 func=INPUT pull=UP
So you need something like:

if [ `raspi-gpio get 12` = "GPIO 12: level=1 func=INPUT pull=UP" ]; then

This works of course. But you can not use the same line in other scripts because the GPIO Pin and the pull changes. So it is much smarter to use “0”. Because then you only have to change the “get pin” and not the whole line for a new script.
There is a reason why I do it this way. :wink:

if [[ $(raspi-gpio get "$pin") == "GPIO $pin: level=1 func=INPUT"* ]]; then

Yes, but i think this is much more complicate than:

if [ `pinctrl level 12` = "0" ]; then

I have so many scripts and some of them are really complicated. So i am happy if it is as simple as possible.
I am particularly proud of my “Project Octopus” which I presented on Discord:

But how does this work if several lines are to be queried synchronously at the same time?
Yes, libgpiod can do something like that.

gpioget --chip 0 28 29 31

reads three lines at the same timestamp:

"28"=active "29"=inactive "31"=inactive

Line 29 is even “ACTIVE_LOW” while the others are “ACTIVE_HIGH”.
Please demonstrate to me how to do this with sysfs.
Of course, I also expect a one-liner for this value query.

Not sure whether this is required in any common use case, where looping through the sysfs nodes (serial) does not work. If such is needed, then indeed, with sysfs it is difficult, if not impossible (even when hacking some semi-parallel reads into the script).

As said, I do not do much which GPIO, all I said is that the easiness of a sysfs has advantages, and I listed more than the maybe advantage of saving some characters in a script. Why not just leave sysfs in place and have libgpio/gpiod additionally? Similarly, why does RPi camera module 3 not provide a simple MJPEG /dev/video0, to preserve the old behaviour, while libcamera reads from the many other /dev/video* device not that are generated anyway? I guess there are reasons why those were done as breaking changes, instead of extensions, but I do not know them.

You complained about the need to use grep and awk in OP, where I would agree that the need for additional external command calls is a real downside, performance/resource-wise and also since it theoretically decreases portability. While bash can do most of this as well with ${var#/%// like string manipulation, this is indeed nasty to write and hard to read. However, in your case it is only a wildcard and a variable, which you use anyway (the pin?), so really nothing I personally worry about. The backtick `command` syntax for command substitutions is btw deprecated. Better use $(command) instead: ShellCheck: SC2006 – Use `$(...)` notation instead of legacy backticked `` `...` ``.

Calm down guys.
When someone does something, they usually have a reason for it. I, for example, started with sysfs and now have to rewrite all my scripts. Of course you can do it differently, but it has grown historically and that’s just the way it is.
@MichaIng: Thx for the hint with &(command) i haven’t know that and will do it like this in the future. :+1: Sometimes you do it like this and it works. So why change it? :wink:

1 Like

You can do something like:
if [[ "$(</sys/class/gpio/gpio${SENSOR1}/value)" = "1" || "$(</sys/class/gpio/gpio${SENSOR2}/value)" = "1" || "$(</sys/class/gpio/gpio${SENSOR3}/value)" = "1" ]]; then
It works, but is of course not really a good solution. Specially because it needs a lot of CPU-Power. ATM my “biggest” project querrys 9 sensors and took about 35% of CPU-Power on a Pi4. :see_no_evil: I migrate it now to “raspi-gpio” and I am curious to see how it will affect the cpu load.
Edit: After switching to “raspi-gpio” CPU-Power goes down to about 3%. :sunglasses:

ATM it looks like this:
Sysfs → Depracted
Wiringpi → Depracted
raspi-gpio → Depracted
gpiod → It gives v1 and v2 and some functions are not compatible
pinctrl → Works for me

So for me “pinctrl” is the alternative ATM. I can use it this way and it works:

if [ $(pinctrl lev ${PIR_PIN}) = “0” ]; then
some command

The only disadvantage is that you have to build it from the sources:

apt update;apt install cmake libfdt-dev build-essential git
cd /tmp;git clone;cd /tmp/utils/pinctrl/;cmake .;make;make install

1 Like