-2

I would like to execute a piece of code every 10 seconds. I have found an example on this forum, but have some issues with my implementation.

package robomow;

import robomow.SI7021;
import robomow.SGP30;
import com.pi4j.io.i2c.I2CFactory;
import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Environment {
  long delay = 10000;
  LoopTask task = new LoopTask();
  Timer timer = new Timer("TaskName");

  public void start() {
    timer.cancel();
    timer = new Timer("Environment");
    SI7021 si7021 = new SI7021();
    SGP30 sgp30 = new SGP30();
    Date executionDate = new Date();
    timer.scheduleAtFixedRate(task, executionDate, delay);
  }

  private class LoopTask extends TimerTask {
    public void run() {
      System.out.printf("Humidity = %.0f  Temperature = %.2f \n", si7021.GetHumidity(), si7021.GetTemperature());
      System.out.printf("eCO2 = %d ppm TVOC = %d \n", sgp30.getECO2(), sgp30.getTVOC());
    }
  }

  public static void main(String[] args) throws InterruptedException,
  IOException,
  I2CFactory.UnsupportedBusNumberException {

    Environment EnvironmentTask = new Environment();
    SI7021 si7021 = new SI7021();
    SGP30 sgp30 = new SGP30();

    EnvironmentTask.start();

  }
}

I get this error, pointing to si7021:

Environment.java:28: error: cannot find symbol
System.out.printf("Humidity = %.0f  Temperature = %.2f \n", si7021.GetHumidity(), si7021.GetTemperature());
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
bzc0fq
  • 579
  • 1
  • 3
  • 18

3 Answers3

3

The variables you are declaring cannot be accessed inside the TimerTask; you should consider moving them inside the class.

    private class LoopTask extends TimerTask {
            SI7021 si7021;
            SGP30 sgp30;
            public LoopTask() {
                try {
                 si7021 = new SI7021();
                 sgp30 = new SGP30();
                } catch(Exception e){
                     //handle exception
                }
            }
            public void run() {
                    System.out.printf("Humidity = %.0f  Temperature = %.2f \n", si7021.GetHumidity(), si7021.GetTemperature());
                    System.out.printf("eCO2 = %d ppm TVOC = %d \n", sgp30.getECO2(), sgp30.getTVOC());
            }
    }
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • This was the first thing I have done, but it resulted in different errors: Environment.java:27: error: unreported exception IOException; must be caught or declared to be thrown SI7021 si7021= new SI7021();.... and pointing to 'new'. Any idea why? – bzc0fq Jan 03 '21 at 18:28
  • this time I got: Environment.java:32: error: unreported exception UnsupportedBusNumberException; must be caught or declared to be thrown si7021 = new SI7021(); and other 7 errors like before... – bzc0fq Jan 03 '21 at 18:57
  • @bzc0fq I've updated my answer, but you should just directly catch all the thrown exceptions instead of a general `Exception`. – Unmitigated Jan 03 '21 at 19:11
  • OK. I think I understand. I have updated the code with thrown exceptions and it compiles now and run fine. Thank you for your help. – bzc0fq Jan 03 '21 at 19:49
  • @bzc0fq No problem. – Unmitigated Jan 03 '21 at 19:50
0

The Answer by iota correctly solved your direct problem. But looking at the bigger picture, you are using obsolete classes. The modern approach with executor service and runnable is easier and simpler.

Avoid the legacy classes

The Timer and TimerTask classes were supplanted with the executor service framework in Java 5 and later.

Likewise, the terrible Date class was supplanted years ago by the modern java.time classes defined in JSR 310. Replaced specifically by java.time.Instant.

Environment class

Let's define your Environment class. This class monitors two pieces of equipment that sample the environment, and reports the current readings when asked via its report method.

package work.basil.example;

import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.*;

public class Environment
{
    private SI7021 si7021 = new Environment.SI7021();
    private SGP30 sgp30 = new Environment.SGP30();

    public void report ( )
    {
        System.out.println( "------------|  Environment Report at " + Instant.now().truncatedTo( ChronoUnit.SECONDS ) + "  |------------------------" );
        System.out.printf( "Humidity = %.0f  Temperature = %.2f \n" , si7021.getHumidity() , si7021.getTemperature() );
        System.out.printf( "eCO2 = %d ppm TVOC = %d \n" , sgp30.getECO2() , sgp30.getTVOC() );
    }

    class SI7021
    {
        public float getHumidity ( )
        {
            return ThreadLocalRandom.current().nextFloat() * 100;
        }

        public float getTemperature ( )
        {
            return ThreadLocalRandom.current().nextFloat() * 100;
        }
    }

    class SGP30
    {
        public int getECO2 ( )
        {
            return ThreadLocalRandom.current().nextInt( 1 , 100 );
        }

        public int getTVOC ( )
        {
            return ThreadLocalRandom.current().nextInt( 1 , 100 );
        }
    }
}

Runnable

Define your task as a Runnable object having a run method.

Using lambda syntax, that would simply be:

Runnable task = ( ) -> environment.report() ;

Or use a method reference.

Runnable task = environment :: report ;

Or, if you are not comfortable with the modern syntax, use an anonymous class.

Runnable task = new Runnable()
{
    @Override
    public void run ( )
    {environment.report();}
};

Scheduled executor service

The ScheduledExecutorService interface repeatedly runs a task, a Runnable. You have a choice of scheduleAtFixedRate​ or scheduleWithFixedDelay, so read the Javadoc to decide which kind of cadence fits your needs.

Be sure to gracefully shutdown your executor service. Otherwise, its backing thread pool may run indefinitely, like a zombie ‍♂️. We use a try-finally to make sure the executor service is shutdown. FYI, in the future when Project Loom arrives, ExecutorService will be AutoCloseable. We will then be able to use try-with-resources syntax for simpler approach to do the shutdown.

    public static void main ( String[] args )
    {
        System.out.println( "INFO - Starting the scheduled executor service generating Environment reports. " + Instant.now() );
        ScheduledExecutorService scheduledExecutorService = null;
        try
        {
            Environment environment = new Environment();
            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
            Runnable task = environment :: report ;
            scheduledExecutorService.scheduleAtFixedRate(
                    task ,                                    // Implements `Runnable`.
                    0 ,                                       // Initial delay.
                    Duration.ofSeconds( 10 ).toSeconds() ,    // Period
                    TimeUnit.SECONDS )                        // Unit of time for both delay and period.
            ;
            // … do other stuff
            try { Thread.sleep( Duration.ofMinutes( 1 ).toMillis() ); } catch ( InterruptedException e ) { e.printStackTrace(); }  // Give our demo a chance to run a while.
            System.out.println( "INFO - Will shutdown the scheduled executor service generating Environment reports. " + Instant.now() );
        }
        finally
        {
            if ( Objects.nonNull( scheduledExecutorService ) ) { scheduledExecutorService.shutdown(); }
        }
    }

When run:

INFO - Starting the scheduled executor service generating Environment reports. 2021-01-04T07:46:54.494330Z
------------|  Environment Report at 2021-01-04T07:46:54Z  |------------------------
Humidity = 95  Temperature = 40.71 
eCO2 = 99 ppm TVOC = 1 
------------|  Environment Report at 2021-01-04T07:47:04Z  |------------------------
Humidity = 72  Temperature = 92.15 
eCO2 = 25 ppm TVOC = 42 
------------|  Environment Report at 2021-01-04T07:47:14Z  |------------------------
Humidity = 52  Temperature = 94.01 
eCO2 = 85 ppm TVOC = 89 
------------|  Environment Report at 2021-01-04T07:47:24Z  |------------------------
Humidity = 80  Temperature = 1.60 
eCO2 = 10 ppm TVOC = 78 
------------|  Environment Report at 2021-01-04T07:47:34Z  |------------------------
Humidity = 64  Temperature = 44.97 
eCO2 = 50 ppm TVOC = 40 
------------|  Environment Report at 2021-01-04T07:47:44Z  |------------------------
Humidity = 1  Temperature = 31.63 
eCO2 = 20 ppm TVOC = 69 
------------|  Environment Report at 2021-01-04T07:47:54Z  |------------------------
Humidity = 30  Temperature = 26.88 
eCO2 = 2 ppm TVOC = 86 
INFO - Will shutdown the scheduled executor service generating Environment reports. 2021-01-04T07:47:54.516543Z

In real work, surround the innards of your Runnable with a try-catch to catch any unexpected exceptions (and maybe errors). An exception/error bubbling all the way up to the scheduled executor service causes the service to halt silently, with no further executions performed.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
-1

You need a class that extends TimerTask and override the public void run() method, which will be executed everytime you pass an instance of that class to timer.schedule() method.

class Hello extends TimerTask { 
 public void run() { 
 System.out.println("Hello World!"); 
 }  
}  
// And From your main() method or any other method 
 Timer timer = new Timer(); 
 timer.schedule(new Hello(), 0, 100000);//10 Min
Abdelmjid Asouab
  • 170
  • 4
  • 15