
Pi4J V5.0.0: Work in Progress
What is Pi4J?
Pi4J is an open-source Java library that gives your Java application access to the hardware pins of a Raspberry Pi and other single-board computers. With it, you can blink an LED, read a button, or talk to sensors, displays, and motor controllers over GPIO, PWM, I2C, SPI, and serial, all from plain Java code and without writing any C. The project started more than ten years ago, is now part of the Commonhaus Foundation, and is maintained by a small team of volunteers.
Since V2, Pi4J uses a plugin architecture, and with the FFM API (Foreign Function & Memory, final since Java 22), the FFM plugin talks directly to the Linux kernel without the native C libraries of earlier versions. That change opened the door to other boards and architectures, like RISC-V, and to the cleanup described below. On top of the core library, Pi4J Drivers provides ready-to-use code for common sensors and components, and there is even a Quarkus extension.
This post was first published on the Pi4J website and gives an overview of what is coming in the next major version.
Towards V5.0.0
Since the 4.0.2 release in June ‘26, the main branch of the Pi4J core repository moved to 5.0.0-SNAPSHOT, and a lot has happened since then: about 300 commits and more than 80 merged pull requests! This post gives an overview of what is changing and who is making it happen.
There is no release date for V5.0.0 yet. Several issues and pull requests are still in progress, and we want to get the API right before releasing, as V5 is the moment to clean up things we couldn’t change in a minor release. If you want to try it out, the snapshot builds are published automatically for every change on main.
A much leaner core
The biggest theme of V5 is cleanup. Pi4J has grown over many years and a lot of code was no longer used, duplicated, or made things more complicated than needed. A selection of the changes:
- Platforms are removed (#650), together with the platform autodetect option (#688).
- Providers are removed (#782), turning a plugin into a factory for a
Context. Minimal stubs remain for the old, prominently documented ways to create IO instances (#790). - Properties and name-based IO creation are removed (#652, #674), as well as the binding and group stubs (#653), PWM presets (#693), the deprecated
DeferredDelay(#640), and other unused metadata and types (#706, #792). - The old Raspberry Pi plugin implementation and the never-used analog GPIO implementation are removed (#664, #665). The FFM plugin is the way forward.
- The internal runtime is merged into
DefaultContext(#660), and write access to the IO registry is no longer exposed (#658). - Config classes no longer depend on the context (#711 and others), bringing them closer to plain DTOs, and IO instances are getting rid of their
Contextdependency (#769, #791). - Intermediate base classes are removed, like
GpioBaseand the provider base classes (#776, #778).
One clear way to create IO instances
Over the years, many different ways to create an IO instance were added. V5 settles on one canonical approach (#704, #728): use <IOTYPE>.newConfigBuilder() and pass the config to context.create(...). Other creation paths are deprecated (with the version in the annotation) or marked as internal, and the remaining internal calls to them have been removed (#733, #735, #738). Devices are now registered while they are created (#734).
Shutting down is simplified as well: the confusing combination of close() and shutdownInternal() is replaced by a single close() method (#768), with several fixes for close ordering and robustness (#677, #678, #755, #780).
Falling back to mocks
A long-standing request (#619) is now possible: run on real hardware when it’s available, and automatically fall back to mocks on other systems, for instance on your development PC (#715). Mock providers now have a lower priority, so they no longer take precedence over real providers. The mock drivers themselves were also reworked into a proper test framework, including a GPIO mock driver (#651).
New and improved IO features
- Parallel port: a new
ParallelPortIO type to read or write multiple GPIOs simultaneously as one value, with direction control at runtime (#727, #740, #765, #785). Event support is in progress in #788. - PWM: frequency and duty cycle are now
doublevalues, so you can use 1.5 Hz or a 33.3% duty cycle (#644, #646), a refactored and optimized FFM PWM implementation (#701), and improved documentation (#759). - I2C: implementations now only need to provide
writeThenRead, as defaults for the other methods are built on top of it (#744, #746).read()now returns unsigned values (#753), and the limitedFILEimplementation is removed (#762). - SPI: support for chunked transfers (#666).
- Digital output: an initial state in the FFM implementation (#663), and
blink,pulse, etc. moved to aDigitalOutputOperationshelper (#749). - GPIO: the FFM GPIO code is refactored to reduce duplication (#698).
More boards: RISC-V and better detection
- RISC-V support (#697): the FFM provider now asks the OS linker to find native libraries instead of using hardcoded paths per architecture. Read more in RISC-V Support Landing in Pi4J V5.
- A
LineHelperfor non-Raspberry Pi boards (#694), following the experiments on Banana Pi and NVIDIA Jetson Nano. - Board detection with revision codes (#682): Raspberry Pi revision codes are parsed into memory size, processor, and board type, as recommended by Raspberry Pi, so new revisions of existing boards are recognized without code changes. The 16GB Compute Module 5 is also supported now (#673).
- Friendlier FFM startup: each provider is registered separately, so a missing Linux group only disables the related provider, and the permission message suggests the correct
usermod -aGcommand (#757, #758). Newer kernel versions are handled in the builds and tests (#662, #760).
Build, release, and documentation
- Java 25 and Maven 4 (#612).
- Automated releases from
mainwith JReleaser (#685), aligned with the Commonhaus release requirements and the same approach as Pi4J Drivers, plus several fixes to make sure snapshots are actually published (#770, #771, #772). - The
module-infofiles are replaced by anAutomatic-Module-Name(#775). Whether the FFM plugin should get a named module again is still being discussed in #795. - Improved JavaDoc for all public methods (#667, #668).
- Smoke test updates for the smoke test PCB (#676, #783).
- An architecture map: every pull request now gets a comment showing which components it changes, based on a groma.md architecture map of the project (#786).
Still in progress
Before V5.0.0 can be released, a number of topics are still open, for example:
- Parallel port events (#788, #789).
- Hardware detection with the FFM plugin (#645, #642).
- Further config cleanup (#794, #705, #714, #731) and removing the
Describable/Identitycomplex (#730). - Removing the remaining
Contextdependency from IO instances (#764). - CRaC checkpoint/restore support for open IO (#797, #798).
- 1-Wire support (#429, #435), analog pins (#699), and software PWM in the FFM plugin (#556).
- A possible issue with FFM
DigitalInputdebounce (#796).
As V5 contains breaking API changes, we will also update the documentation and examples on the Pi4J website before the release. Feedback is very welcome! Try the snapshot with your project and let us know in the issues or discussions what works and what breaks.
Thank you
A huge thank you to everyone who contributed code, reviews, ideas, and testing to the upcoming V5:
- Stefan Haustein (@stefanhaustein), who drove most of the API cleanup.
- @IAmNickNack, for the parallel port, the base class cleanups, and many fixes.
- Nick Gritsenko (@DigitalSmile), for RISC-V support, the test framework, and the GPIO, PWM, I2C, and SPI improvements in the FFM plugin.
- Robert von Burg (@eitch), for reviewing and merging, and the release preparations.
- Tom Aarts (@taartspi), for the smoke tests and the I2C and close fixes.
- Matti Tahvonen (@mstahv), for the FFM startup and I2C improvements.
- Peter (@pjbosco), for the revision code parsing and Compute Module 5 support.
- Fanon Jupkwo (@FanJups) and Tiza Talla (@kurocifer), for the migration to Maven 4.
- Matt Van Horn (@mvanhorn), for guarding the deploy workflows in forks.
- Dariusz Zbyrad (@dariuszzbyrad), for the ongoing work on 1-Wire support.
- Frank Delporte (@FDelporte), for the release automation, JavaDoc, and build work.
You can follow all the changes on GitHub in the commit history.
Found a mistake, or something to add? Edit this page on GitHub





