DIOZero - a Java Device I/O wrapper for GPIO / I2C / SPI control

Build Status Maven Central Maven Central status License: MIT Javadoc Documentation Status

A Device I/O library written in Java that provides an object-orientated interface for a range of GPIO / I2C / SPI devices (LEDs, buttons, sensors, motors, displays, etc) connected to Single Board Computers like the Raspberry Pi. Actual GPIO / I2C / SPI device communication is delegated to pluggable service providers for maximum compatibility across different boards. This library is known to work on the following boards: all models of the Raspberry Pi, Odroid C2, BeagleBone Black, C.H.I.P and Asus Tinker Board. It should be portable to any Single Board computer that runs Linux and Java 8.

This library makes use of modern Java features such as automatic resource management, Lambda Expressions and Method References where they simplify development and improve code readability.

Created by Matt Lewis (email [email protected]) (blog), inspired by GPIO Zero and Johnny Five. If you have any issues please use the GitHub issues page. For any other comments or suggestions, please use the diozero Google Group.


The aim of this library is to encapsulate real-world devices as classes with meaningful operation names, for example, LED (on / off), LDR (get luminosity), Button (pressed / released), Motor (forward / backwards / left / right). All devices implement Closeable hence will get automatically closed by the try (Device d = new Device()) { d.doSomething(); } statement. This is best illustrated by some simple examples.

Note "Pin Numbering"

All pin numbers are device native, i.e. Broadcom for the Raspberry Pi, ASUS for the Tinker Board. Pin layouts:

LED control:

try (LED led = new LED(pin)) {
    led.blink(0.5f, 0.5f, 10, false);

Turn on an LED when you press a button:

try (Button button = new Button(buttonPin, GpioPullUpDown.PULL_UP); LED led = new LED(ledPin)) {

Or a random LED flicker effect:

Random random = new Random();
try (PwmLed led = new PwmLed(pin)) {
    DioZeroScheduler.getNonDaemonInstance().invokeAtFixedRate(RANDOM::nextFloat, led::setValue, 50, 50, TimeUnit.MILLISECONDS);

All devices are actually provisioned by a Device Factory with a default NativeDeviceFactory for provisioning via the host board itself. However, all components accept an optional Device Factory parameter for provisioning the same set of components via an alternative method. This is particularly useful for GPIO expansion boards and Analog-to-Digital converters.

!!! note "Device Factory" Unless you are implementing a new device you shouldn't need to use any of the Device Factory interfaces or helper classes (within the com.diozero.internal package).

Some boards like the Raspberry Pi provide no analog input pins; attempting to create an AnalogInputDevice such as an LDR using the Raspberry Pi default native device factory would result in a runtime error (UnsupportedOperationException). However, support for Analog to Digital Converter expansion devices such as the MCP3008 has been added which are implemented as analog input device factories hence can be used in the constructor of analog devices like LDRs:

try (McpAdc adc = new McpAdc(McpAdc.Type.MCP3008, chipSelect); LDR ldr = new LDR(adc, pin, vRef, r1)) {

Repeating the previous example of controlling an LED when you press a button but with all devices connected via an MCP23017 GPIO expansion board:

try (MCP23017 mcp23017 = new MCP23017(intAPin, intBPin);
        Button button = new Button(mcp23017, inputPin, GpioPullUpDown.PULL_UP);
        LED led = new LED(mcp23017, outputPin)) {

Analog input devices also provide an event notification mechanism. To control the brightness of an LED based on ambient light levels:

try (McpAdc adc = new McpAdc(McpAdc.Type.MCP3008, chipSelect); LDR ldr = new LDR(adc, pin, vRef, r1); PwmLed led = new PwmLed(ledPin)) {
    // Detect variations of 10%, get values every 50ms (the default)
    ldr.addListener((event) -> led.setValue(1-event.getUnscaledValue()), .1f);

Supported Devices

diozero has out of the box support for the following Single Board Computers:

The builtin sysfs provider is designed to be portable across different boards. In addition, the JDK Device I/O providers add an alternative method of compatibility, for example on the Udoo Quad.

Getting Started

Snapshot builds of the library are available in the Nexus Repository Manager. For convenience a ZIP of all diozero JARs will also be available on Google Drive.

Javadoc for the core library is also available via javadoc.io.

Unfortunately Java doesn't provide a convenient deployment-time dependency manager such as Python's pip therefore you will need to manually download all dependencies and setup your classpath correctly. You can do this either via setting the CLASSPATH environment variable or as a command-line option (java -cp <jar1>:<jar2>). The dependencies have been deliberately kept to as few libraries as possible, as such this library is only dependent on tinylog v1.3.6.

To compile a diozero application you will need 2 JAR files - tinylog, and diozero-core. To run a diozero application, you will also need one of the supported device provider libraries and the corresponding diozero provider wrapper library. Note the built-in sysfs device provider gives maximum portability but has some limitations such as not being able to configure internal pull up/down resistors.

SBC Provider Provider Jar diozero wrapper-library
All sysfs N/A Built-in
32bit boards JDK Device I/O 1.0 dio-1.0.1.jar diozero-provider-jdkdeviceio10-<version>.jar
32bit boards JDK Device I/O 1.1 dio-1.1.jar diozero-provider-jdkdeviceio11-<version>.jar
Raspberry Pi Pi4j pi4j-core-1.1.jar diozero-provider-pi4j-<version>.jar
Raspberry Pi wiringPi pi4j-core-1.1.jar diozero-provider-wiringpi-<version>.jar
Raspberry Pi pigpio pigpioj-java-1.0.1.jar diozero-provider-pigio-<version>.jar
Raspberry Pi, Odroid C2 mmap N/A diozero-provider-mmap-<version>.jar

To get started I recommend first looking at the classes in com.diozero.sampleapps. To run the LEDTest sample application using the pigpioj provider:

sudo java -cp tinylog-1.1.jar:diozero-core-0.9-SNAPSHOT.jar:diozero-sampleapps-0.9-SNAPSHOT.jar:diozero-provider-pigpio-0.9-SNAPSHOT.jar:pigpioj-java-1.0.1.jar com.diozero.sampleapps.LEDTest 12

For an experience similar to Python where source code is interpreted rather than compiled try Groovy (sudo apt-get update && sudo apt-get install groovy2). With the CLASSPATH environment variable set as per the instructions above, a simple test application can be run via the command groovy <filename>. There is also a Groovy shell environment groovysh.

A Groovy equivalent of the LED controlled button example:

import com.diozero.Button
import com.diozero.LED
import com.diozero.util.SleepUtil

led = new LED(12)
button = new Button(25)

button.whenPressed({ led.on() })
button.whenReleased({ led.off() })

println("Waiting for button presses. Press CTRL-C to quit.")

To run:

sudo groovy -cp $CLASSPATH test.groovy

__Note "Groovy JAVA_HOME config when running via sudo"__

I was getting the error:

groovy: JAVA_HOME is not defined correctly, can not execute: /usr/lib/jvm/default-java/bin/java

I tried setting JAVA_HOME in /etc/environment and /etc/profile.d/jdk.sh to no affect. Eventually the following fixed it for me. Please let me know if there is a better way to fix this issue.

ln -s /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt /usr/lib/jvm/default-java


This library provides support for a number of GPIO / I2C / SPI connected components and devices, I have categorised them as follows:


I've done some limited performance tests (turning a GPIO on then off, see GpioPerfTest) on a Raspberry Pi 2 and 3 using the various native device factory providers. I've also run tests using JNI APIs directly without going via my DIO-Zero wrapper to assess the overhead of using my library (see WiringPiRawPerfTest and PigpioPerfTest) - the overhead of DIO-Zero is approximately 25% for both pigpio and wiringPi. Here are the results:

Provider Device Frequency (kHz)
Pi4j 1.0 Pi2 0.91
JDK DIO 1.1 Pi2 8.23
Pi4j 1.1 Pi2 622
pigpio Pi2 2,019
pigpio Pi3 2,900
pigpio (JNI) Pi2 2,509
pigpio (JNI) Pi3 3,537
wiringPi Pi2 2,640
wiringPi Pi3 3,446
wiringPi (JNI) Pi2 3,298
wiringPi (JNI) Pi3 4,373
mmap Pi3 7,686
mmap (JNI) Pi3 11,007


For a discussion on why Pi4j 1.0 was so slow, see this issue. These results are in-line with those documented in the book "Raspberry Pi with Java: Programming the Internet of Things". For reference, the author's results were:

Library Frequency (kHz)
Pi4j 1.0 0.751
JDK DIO 1.0 3.048
wiringPi (direct) 1,662


This project is hosted on GitHub, please feel free to join in:


Release History


This work is provided under the MIT License.