diozero

repository·main·Indexed 43 days ago

https://github.com/mattjlewis/diozero

A Java Device I/O wrapper providing an object-oriented interface for controlling GPIO, I2C, and SPI devices on Single Board Computers such as Raspberry Pi, Odroid C2, BeagleBone, C.H.I.P, and ASUS Tinker Board. It features a layered architecture with pluggable service providers, including a Firmata protocol provider, and supports high-level abstractions for LEDs, buttons, stepper motors, and OLED displays.

Tokens
30.4K
Snippets
114
Records
150
Agent score
53%

What's inside diozero

  1. Overview of diozero for Device I/O

    main

    diozero is a Java-based Device I/O library designed to provide an object-oriented interface for controlling GPIO, I2C, and SPI devices (such as LEDs, buttons, sensors, motors, and displays) on Single Board Computers (SBCs).

    Key characteristics:

    • Pluggable Service Providers: Actual hardware communication is delegated to pluggable providers, allowing the library to work across different boards.
    • Supported Hardware: Works on Raspberry Pi (all models), Odroid C2, BeagleBone (Green and Black), C.H.I.P, and ASUS Tinker Board.
    • Portability: Designed to be portable to any Linux-based SBC running Java 11+.
    • Modern Java: Utilizes automatic resource management (try-with-resources), Lambda expressions, and Method References.
  2. Overview of diozero hardware interfaces and devices

    main

    diozero provides a portable API for physical computing across various Single Board Computers (SBCs) and micro-controllers. It supports direct interfacing with low-level protocols and high-level device abstractions.

    Low-level Interfaces

    • GPIO: Digital I/O control.
    • I2C: Inter-Integrated Circuit communication.
    • SPI: Serial Peripheral Interface.
    • Serial: Serial device communication.

    High-level Device Abstractions

    • Simple Devices: LDR (Light Dependent Resistor), Button, and Motor (via MotorBase).
    • Complex Sensors: Environmental sensors like the BME680 (Bosch Sensortec Gas Sensor).
  3. Understand the diozero package structure

    main

    The diozero API is organized into four primary packages that separate low-level interface logic from high-level device abstractions:

    • com.diozero.api: The core layer. Use this for direct interfacing with hardware protocols like GPIO, I2C, SPI, and Serial.
    • com.diozero.devices: The device layer. Use this to interact with physical components (e.g., LED, Button, Motors) and sensor components (e.g., BME680, MCP3008).
    • com.diozero.sbc: The board layer. Use this to access and describe the Single Board Computer (SBC) currently in use.
    • com.diozero.util: The utility layer. Provides helper functions for CRC calculation, number range conversions, and servo pulse duration calculations.
  4. Supported sensor devices in diozero

    main

    diozero provides built-in support for a wide variety of sensor devices across different measurement types, including ambient light, temperature, barometric pressure, humidity, gas (VOC), distance, and RFID.

    Supported devices include:

    • Ambient Light: Rohm BH1750, ams TSL2561
    • Temperature & Pressure: Bosch Sensortec BMP180, BMP280, BME280, BME680, BME688, STMicroelectronics LPS25H, Texas Instruments LM73
    • Humidity & Temperature: STMicroelectronics HTS221
    • Gas / Air Quality: Bosch Sensortec BME680, BME688, Sensirion SGP30
    • Distance: Sharp GP2Y0A21YK, HC-SR04 (Ultrasonic)
    • RFID: Mifare MFRC522
    • Temperature (Analog/1-wire): TMP36, and various 1-wire sensors (DS18S20, DS1822, DS18B20, DS1825, DS28EA00, MAX31850K)
  5. Use the Firmata Provider for device I/O

    main

    The diozero-provider-firmata implements the Firmata protocol as a diozero provider. It allows for device control via either serial or sockets communication.

    While it is designed to be used through the standard diozero API, you can also use the FirmataAdapter classes directly if you wish to bypass the diozero abstraction. These adapters are located in the com.diozero.internal.provider.firmata.adapter package.

  6. Use memory-mapped GPIO for pull-up/pull-down resistor support

    main

    Linux kernels prior to 5.5 do not support pull-up/pull-down resistors via the standard gpiod interface. To configure these resistors on supported boards, diozero uses an internal memory-mapped GPIO implementation.

    This requires the user to have access to the corresponding memory file: /dev/gpiomem or /dev/mem.

  7. High-performance GPIO via Memory Mapped GPIO (mmap)

    main

    For very high performance, diozero can access GPIO registers directly via the /dev/gpiomem device file. The built-in default provider uses this method, enabling toggle rates as high as 24MHz on a Raspberry Pi 4.

    Supported SBCs for mmap:

    • Raspberry Pi (all variants)
    • FriendlyArm / Allwinner H3 Sun8i CPU (e.g., NanoPi Duo2 / NanoPi Neo)
    • OrangePi Zero+ (Allwinner H5) / One+ (Allwinner H6)
    • ASUS TinkerBoard
    • Odroid C2
    • Next Think Co CHIP (Allwinner sun4i/sun5i)

    Note: Accessing /dev/gpiomem may require running as root.

  8. How diozero's layered architecture works

    main

    diozero uses a layered architecture to provide portability across different Single Board Computers (SBCs) and micro-controllers. The architecture consists of three main layers:

    1. Device API (com.diozero.devices): High-level, object-oriented classes representing physical devices (e.g., LED, Button, Motor). These are the primary classes used by developers to interact with hardware using meaningful operation names.
    2. Base I/O API (com.diozero.api): Provides the fundamental interfaces and classes for low-level communication, including GPIO, I2C, SPI, and Serial.
    3. Provider Layer: Handles the actual hardware communication. This is split into the Service Provider Interface (SPI) (com.diozero.internal.spi) and specific Service Provider implementations (e.g., the built-in provider in com.diozero.internal.provider.builtin).

    This design allows the same Device API code to run on various platforms (Raspberry Pi, Odroid, BeagleBone, etc.) by simply swapping the underlying provider.

  9. Provision GPIO pins using Builders or PinInfo

    main

    When working with GPIO in diozero, follow these best practices for provisioning pins:

    1. Use Builders: Always use the provided static Builder classes instead of calling constructors directly.
    2. Pin Identification: You can provision a pin using either a raw GPIO number or a PinInfo object.
    3. Retrieving PinInfo: To get a PinInfo object, use the lookup methods in a BoardPinInfo instance. This instance is obtained from the device factory via the getBoardPinInfo() method.
    4. Device Factories: For expansion boards like the MCP3008, you must specify the appropriate GPIO or Analog Input device factory. If not specified, diozero defaults to the automatically detected host board.
  10. Understand diozero performance characteristics

    main

    diozero performance varies significantly depending on the chosen provider and the underlying hardware.

    Key takeaways for performance optimization:

    • Built-in (mmap) provider: This is the fastest implementation for GPIO toggling. It uses memory-mapped I/O and provides the highest frequencies (e.g., >27 MHz on a Raspberry Pi 4B 64-bit).
    • pigpio provider: While pigpio itself is fast, using it via diozero (or via JNI in pigpioj) introduces overhead compared to the built-in mmap implementation.
    • Operating System: Using a 64-bit OS can deliver additional performance for the built-in memory-mapped GPIO implementation.
    • Hardware-specific providers: For certain devices like the BeagleBone Black, the BBBioLib provider is significantly faster (1,453 kHz) than the builtin provider (191 kHz).
  11. Read analog inputs and scaled values

    main

    The AnalogInputDevice class allows interfacing with analog devices.

    Key behaviors:

    • Normalization: All raw analog readings are normalized to a range of -1..1 (unscaled).
    • Scaled Readings: You can access scaled readings (e.g., voltage, temperature, distance). To ensure accuracy, you must set the ADC voltage range in the device constructor.
    • Hardware Note: Many boards (like Raspberry Pi) do not have native analog input. You must use expansion boards like an ADC (e.g., MCP3008) to provide this functionality.

    Event Notifications: Analog devices support event listeners, allowing you to trigger actions based on changes in analog values.

    // Example: Using an LDR (Light Dependent Resistor) to control LED brightness via events
    try (McpAdc adc = new McpAdc(McpAdc.Type.MCP3008, 1);
    	LDR ldr = new LDR(adc, 1, 1000);
    	PwmLed led = new PwmLed(18)) {
    	// Detect variations of 10%, get values every 50ms (the default)
    	ldr.addListener(event -> led.setValue(1 - event.getUnscaledValue()), .1f);
    	SleepUtil.sleepSeconds(20);
    }