Wednesday, November 17, 2021

[SOLVED] TimerTask stops running after midnight

Issue

I have a small part of the program that has a timer to take a picture using a usb webcamera through the command line (fswebcam) every 15 minutes.

The code is like this:

public static final String HOME_DIR = System.getProperty("user.home") + "/";
public static final String PGP_DIR = HOME_DIR + "PGP/";

public static final String COLLECTION_DATA_DIR = PGP_DIR + "collectionData/";
public static final String SENSOR_CALIBRATION_DATA = PGP_DIR + "sensorCalibration/";
public static final String PICTURE_DIR = PGP_DIR + "pictures/";
public static final String ALARM_DIR = PGP_DIR + "alarms/";
private class PictureTakerTask extends TimerTask{
        Timer t;
        public void start(){
            if(t != null){
                t.cancel();
                t.purge();
                t = null;
                this.cancel();
            }
            t = new Timer(true);
            t.scheduleAtFixedRate(this, 0, 1000 * 60 * 15); //takes a picture every 15 minutes
        }

        public void stop(){
            if(running) return;
            if(t != null){
                t.cancel();
                t.purge();
                t = null;
            }
            this.cancel();
        }

        @Override
        public void run() {
            
            String filename = getPictureFilename();
            if(filename == null) return;
            Process p;
            try {
                CommIO.printLog("Taking a picture");
                String file;
                light.setGreenPWM(80);
                p = Runtime.getRuntime().exec("fswebcam -r 1920x1080 --no-banner -S 1 " + filename);
                p.waitFor();
                System.out.println ("picture taken with exit value: " + p.exitValue());
                p.destroy();
                light.setGreenPWM(0);
            } catch (Exception e) {
                e.printStackTrace();
                light.setGreenPWM(0);
            }
        }

        private String getPictureFilename(){
            //make folder if it doesn't exist already
            SimpleDateFormat justDate = new SimpleDateFormat("MM-dd-yy");
            String date = justDate.format(new Date());
            String s = PICTURE_DIR + date + "/";
            File picDir = new File(s);
            if(!picDir.exists()){
                if(picDir.mkdir()){
                    Alert alert = new Alert(AlertType.ERROR, "Couldn't make picture directory: " + s, ButtonType.OK);
                }
            }
            //find an unused filename
            String picFileName = s + "plant_01.jpg";
            File tempFile = new File(picFileName);
            int i = 1;
            while (tempFile.exists()) { //finds the next nonexistent name for data spreadsheet
                String num = i < 10 ? "0" + i : "" + i;
                picFileName = s + "plant_" + num + ".jpg";
                i++;
                tempFile = new File(picFileName);
                if(i > 10000) break;
            }
            return picFileName;
        }
    }

The thread starts and works fine, until midnight exactly. It will fail to take pictures the next day. I can't figure out for the life of me why it stops. If I stop and restart the task it will work fine again. If I even take a picture through the terminal outside the program it will work fine again. It just will quit taking pictures by the next day. It even creates the next day's folder, just no pictures. No error messages (that I can find).

Does anybody have any ideas or experience with this? Before you say it, no I can't use motion or Cron because I need to be synchronized with the "light" object in the run() function.


Solution

Answering my own question. Simple mistake, actually:

if(picDir.mkdir()){
    Alert alert = new Alert(AlertType.ERROR, "Couldn't make picture directory: " + s, ButtonType.OK);
}

Forgot the negation of condition. I usually run the program more than once in a day to check other changes, so it makes the folder on the first time, crashes the thread, and runs fine the next couple times I start the program. But when the next day comes around, it makes an Alert and throws a tantrum because it's not on the FX thread. It was difficult to notice because I forgot to actually even show the Alert.

I love java-fx, but it can be so finicky sometimes. Fixed by adding negation, and putting the alert into a Platform.runLater Runnable.



Answered By - James Regenold