Home > Mobile >  Pi4j to use java with raspberry Pi not working
Pi4j to use java with raspberry Pi not working

Time:12-19

I am honestly about to just give up, i've tried so many different possibilities, for multiple weeks now, almost a month, of multiple problems.

I am a new-ish programmer, especially with java, but i have a good understanding about java

I am able to create a maven project no problem, i have no problems with the structure of java itself, but i don't fully understand the pom.xml.

The file compiles just fine, but when i go to start it with java -jar (filename), i get the following output;

Exception in thread "main" java.lang.NoClassDefFoundError: com/pi4j/Pi4J at com.pi.rasberri.Main.main(Main.java:16) Caused by: java.lang.ClassNotFoundException: com.pi4j.Pi4J at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ... 1 more

Heres my pom that i have figuratively almost dismembered;

   (The long links)
<modelVersion>4.0.0</modelVersion>
<groupId>com.pi</groupId>
<artifactId>Rasberri</artifactId>
<version>3.6.1</version>
<packaging>jar</packaging>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>  <dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.32</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.32</version>
    </dependency>
    <dependency>
        <groupId>com.pi4j</groupId>
        <artifactId>pi4j-core</artifactId>
        <version>2.0</version>
    </dependency>
    <dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-plugin-raspberrypi</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-plugin-pigpio</artifactId>
    <version>2.0</version>
</dependency>
</dependencies> <build>
  <plugins>
      <plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2</version> </plugin>    <plugin>    <groupId>org.apache.maven.plugins</groupId>   

maven-jar-plugin 3.1.0 true com.pi.rasberri.Main lib/ true true com.pi.rasberri.Main false true

And my code, which is com.pi.rasberri.Main

    package com.pi.rasberri;

import com.pi4j.Pi4J;
import com.pi4j.io.gpio.digital.DigitalOutput;
import com.pi4j.io.gpio.digital.DigitalState;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {
   
    private static final int PIN_LED = 6;
    
    public static void main(String[] args) throws Exception{
        
       var pi4j = Pi4J.newAutoContext();
        int x = 0;
        
        var ledConfig = DigitalOutput.newConfigBuilder(pi4j)
           .id("led")
           .name("LED Flasher")
           .address(PIN_LED)
           .shutdown(DigitalState.LOW)
           .initial(DigitalState.LOW)
           .provider("pigpio-digital-output");
      
        var led = pi4j.create(ledConfig);
        
        
        while(x != 5){
        
            led.high();
            sleep(1000);
            led.low();
            sleep(500);
            x  ;
        }
    }
    
    static void sleep(int z){
    
        try {
           Thread.sleep(z);
        }   catch (InterruptedException ex) {
           System.out.println("Thread.sleep went fucky wucky");
        }
    }
    }

I would appreciate anything that can even direct me somewhere, because i am quite lost at this point, and of course, if i figure out the answer, i will let everyone know! Thanks in advance

                       **UPDATE**

Thank you, tgdavies, the article you linked https://stackoverflow.com/a/574650/17644313 was the answer to that specific problem!**

Just in case anyone else has the same chain of issues as me;

But with that being said, i ran directly into another error;

[main] INFO com.pi4j.Pi4J - New auto context [main] INFO com.pi4j.Pi4J - New context builder [main] INFO com.pi4j.platform.impl.DefaultRuntimePlatforms - adding platform to managed platform map [id=raspberrypi; name=RaspberryPi Platform; priority=5; class=com.pi4j.plugin.raspberrypi.platform.RaspberryPiPlatform] Exception in thread "main" com.pi4j.provider.exception.ProviderNotFoundException: Pi4J provider [pigpio-digital-output] could not be found. Please include this 'provider' JAR in the classpath. at com.pi4j.provider.impl.DefaultRuntimeProviders.get(DefaultRuntimeProviders.java:238) at com.pi4j.provider.impl.DefaultProviders.get(DefaultProviders.java:147) at com.pi4j.provider.Providers.get(Providers.java:253) at com.pi4j.context.Context.create(Context.java:316) at com.pi4j.internal.IOCreator.create(IOCreator.java:58) at com.pi4j.internal.IOCreator.create(IOCreator.java:96) at com.pi4j.internal.IOCreator.create(IOCreator.java:176) at com.pi.rasberri.Main.main(Main.java:27)

I cleaned the pom.xml a littlebit;

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.32</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.32</version>
    <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.pi4j</groupId>
        <artifactId>pi4j-core</artifactId>
        <version>2.0</version>
    </dependency>
    <dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-plugin-raspberrypi</artifactId>
    <version>2.0</version>
</dependency>
<dependency>
    <groupId>com.pi4j</groupId>
    <artifactId>pi4j-plugin-pigpio</artifactId>
    <version>2.0</version>
</dependency>
</dependencies>
  

<build>
      <plugins>  <!--Package all libraries classes into one runnable jar -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
            <configuration>
                <archive>
                    <manifest>
                <mainClass>com.pi.rasberri.Main</mainClass>
                    </manifest>
                </archive>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
            </configuration>
        </plugin>    
</plugins>
</build>
</project>

At this point, i know of atleast 2 possibilities,

  1. The code just needs to be run on the raspberry pi
  2. I have entered the classpaths incorrectly

But i honestly dont really know as to where to start troubleshooting I've tried a few things, one of which being to try another method of compiling the files, but the other method just resulted in a even longer string of errors.

What should i try next? Thanks in advance! And thanks to anyone who has suggested troubleshooting steps thus far!

Oh, and the target is to hopefully just create a singular jar file to execute on the raspberry pi

update

I tried to run it on the Raspberri pi, and it resulted in the same error so it's not that

CodePudding user response:

Thanks tgdavies, MadProgrammer, and khmarbaise for the answers, the fix was to create a fat jar, which is basically a jar file that contains all the dependencies in one file, example can be found in the original question/comments

Now, as to the other problem, the issue is with this bit of code;

 var ledConfig = DigitalOutput.newConfigBuilder(pi4j)
       .id("led")
       .name("LED Flasher")
       .address(PIN_LED)
       .shutdown(DigitalState.LOW)
       .initial(DigitalState.LOW)
       .provider("pigpio-digital-output");
  
    var led = pi4j.create(ledConfig);

As to why, i am still trying to figure out, but i will edit this answer when i figure that out,

The reason the second error is caused, is beacause currently pi4j 2.0 does not support fat jars

Link; https://github.com/Pi4J/pi4j-v2/issues/129

and just in case anyone is wondering, heres the final POM.xml;

(The long links that are automatically created)

   <modelVersion>4.0.0</modelVersion>
   <groupId>com.pi</groupId>
   <artifactId>Rasberri</artifactId>
   <version>3.6.1</version>
   <packaging>jar</packaging>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
       <version>1.7.32</version>
    </dependency>
    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
      <version>1.7.32</version>
    </dependency>
    <dependency>
        <groupId>com.pi4j</groupId>
        <artifactId>pi4j-core</artifactId>
        <version>2.0</version>
    </dependency>
    <dependency>
       <groupId>com.pi4j</groupId>
       <artifactId>pi4j-plugin-raspberrypi</artifactId>
      <version>2.0</version>
   </dependency>
   <dependency>
       <groupId>com.pi4j</groupId>
       <artifactId>pi4j-plugin-pigpio</artifactId>
      <version>2.0</version>
   </dependency>
</dependencies>   

<build>
  <plugins> 
    <plugin> <!-- Fat jar; -->
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
            <archive>
                <manifest>
                    <mainClass>com.pi.rasberri.Main</mainClass>
                </manifest>
            </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
    </plugin>     
</plugins> 

CodePudding user response:

I do not have a Raspberry Pi to do final testing but I think I found a work-around.

Using this answer I managed to get 2021-10-30-raspios-bullseye-armhf-lite.img running in Docker. I built a project using your code and copied all files needed and tried to start it (mypiapp is my jar containing your main-class):

java -cp mypiapp-0.0.1-SNAPSHOT.jar:lib/pi4j-core-2.1.1.jar:lib/pi4j-library-pigpio-2.1.1.jar:lib/pi4j-plugin-pigpio-2.1.1.jar:lib/pi4j-plugin-raspberrypi-2.1.1.jar:lib/slf4j-api-1.7.32.jar:lib/slf4j-simple-1.7.32.jar com.github.fwi.mypiapp.MyPiApp

which then gave me the error:

[main] ERROR com.pi4j.library.pigpio.util.NativeLibraryLoader - Unable to load [libpi4j-pigpio.so] using path: [/lib/armhf/libpi4j-pigpio.so]
java.lang.UnsatisfiedLinkError: /tmp/libpi4j-pigpio1770932771276400506.so: libpigpio.so.1: cannot open shared object file: No such file or directory

which is a bummer. But at least there was no ProviderNotFoundException (which I also could reproduce using the "fat jar with dependencies"). The long java-command appears to prevent that exception from happening.

And I could improve the situation somewhat by running (in Raspbian)

apt install pigpio

and now the long java-command shows:

[main] WARN com.pi4j.library.pigpio.impl.PiGpioNativeImpl - PIGPIO ERROR: PI_INIT_FAILED; pigpio initialisation failed

which is to be expected when running in a Docker container. But at least the native library was found and loaded.

Now for the work-around which might solve the "fat jar" problems. We are gonna borrow some Maven setup and code from Spring. Spring can also build fat-jars and does it a bit more complicated but also better. The pom now looks like (update where needed with your project names):

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.1</version>
    </parent>
    
    <groupId>com.github.fwi</groupId>
    <artifactId>mypiapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <start.class>com.github.fwi.mypiapp.MyPiApp</start.class>
        <pi4j.version>2.1.1</pi4j.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.pi4j</groupId>
            <artifactId>pi4j-plugin-raspberrypi</artifactId>
            <version>${pi4j.version}</version>
        </dependency>
        <dependency>
            <groupId>com.pi4j</groupId>
            <artifactId>pi4j-plugin-pigpio</artifactId>
            <version>${pi4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>${start.class}</mainClass>
                    <layout>ZIP</layout>
                    <executable>false</executable>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Simply run mvn clean package to build the fat-jar. Run it using java -jar mypiapp-fat.jar In my case, it gave the exact same error as when running with the long java-command (i.e. there was no ProviderNotFoundException). So I think this could work on a real Raspberry-Pi (the apt install pigpio might still be required though).

Some notes:

  • the Spring parent sets some good Maven defaults and also sets good defaults for the spring-boot-maven-plugin
  • Java version MUST be set using the java.version property.
  • update start.class with the name of the class containing your main-method.
  • the 3 dependencies in the pom.xml will pull in all other dependencies (dependencies of dependencies)
  • Spring documentation references: packaging and nested-jars launcher options.
  • Related