5

I have a program that will run 24/7 getting frames from a camera, doing processing and sending .jpg images via local network. Generally, I don't want any saving of video to file, however I might want to schedule x minutes of saving on certain occasion (not triggered, scheduled).

I handle video recording by calling VideoWriter as a thread of VideoCamera. I found this to be more accurate to handle writing with correct fps. This process works perfectly when I want to record from the beginning and when I just want to stream. I initiate the camera like this.

import ...
# from custom file import `VideoCamera` which has access to `VideoWriter`
from camera import VideoCamera

video_camera = VideoCamera(
    flip = False, 
    usePiCamera = False, 
    resolution = (640, 480),
    record = False,
    record_duration = None,
    record_timestamp = True
    ) 

The camera can't be initialized twice (can't access same camera twice). So I was thinking about scheduling a stop and restart with new parameters (for example record = True, record_duration = "00:10:00").

I call the script from console (python main.py) which has:

if __name__ == '__main__':
    t = threading.Thread(target=processing_fun, args=())
    t.daemon = True
    t.start()
    print("To see feed connect to " + get_ip_address() + ":5000")
    # to do, read ifconfig and assign IP using raspberry's IP
    app.run(host='0.0.0.0', port = 5000, debug=False)

processing_fun will be dead if I do del(video_camera) because it needs frames from camera. Same for the stream. I'm not sure there's a way to delete the camera without breaking the threads.

Idea to solve the problem

I was thinking about a way to

  1. Do init of video_camera without record
  2. At given moment, cleanly stop main.py (or kill it if not possible)
  3. Restart main.py with new parameters for video_camera
    • This might involve saving a cam_config file, which I'm fine with
  4. repeat 3) and 4) on needed schedule

Places I have looked for help

I have looked here and here but I am not sure how to put things together in a scheduled way.

11
  • Can't you always save the video in a ring buffer and use that if you need it? Commented Feb 17, 2020 at 3:14
  • Interesting, how would you implement scheduled save of the buffer ring in videowriter? Commented Feb 17, 2020 at 3:31
  • Well, you give too less detail to say that. Imo the problem is too broad for Stackoverflow, it can't be answered without providing a whole application. Maybe you can break it down into separate simpler questions. Commented Feb 17, 2020 at 3:50
  • I have an idea, but it depends on one question: Do you have full access to the code in VideoCamera? That is, can you modify it to add functionalities? Commented Feb 17, 2020 at 4:33
  • 1
    I actually think cron is a good option. It decouples the scheduling from the camera program. What I think unclean is the stopping/starting of program just to change a simple behavior. I still think cron is a good solution, but it's your choice which direction to pursue. Commented Feb 18, 2020 at 16:03

1 Answer 1

3
+25

You can use the crontab to schedule your scripts, and you mentioned you can also kill your scripts using the crontab. You can create a startup.sh script and some sort of shutdown.sh which will manage your schedule.

Below is an example:

Your python script say your_script.py:

import ...
# from custom file import `VideoCamera` which has access to `VideoWriter`
from camera import VideoCamera

video_camera = VideoCamera(
    flip = False, 
    usePiCamera = False, 
    resolution = (640, 480),
    record = False,
    record_duration = None,
    record_timestamp = True
    ) 


first_arg = sys.argv[1]
second_arg = sys.argv[2]
third_arg = sys.argv[3]

# pass the above arguments here in the function
if __name__ == '__main__':
    t = threading.Thread(target=processing_fun, args=())
    t.daemon = True
    t.start()
    print("To see feed connect to " + get_ip_address() + ":5000")
    # to do, read ifconfig and assign IP using raspberry's IP
    app.run(host='0.0.0.0', port = 5000, debug=False)

cron-python script to schedule your python script:

Name this script as schedule_cron_python.py and call this to manage your schedule. Here you can keep this whole code within a function and also pass arguments to this cron script like the time-date on which you want to schedule and in turn manage this with another cron script. (1st option)


from crontab import CronTab
import os
import sys
cron = CronTab(user='sshuser')

job1 = cron.new(command="python3 your_script.py 'arg1' 'arg2' 'arg3'")
job1.hour.on(5) # Mention your own time here
job1.minute.on(30)

for item in cron:
    print(item)
print(job1.enable())
cron.write()
#print(os.getcwd())

2nd Option:

Create separate startup.sh and shutdown.sh

These files will contain just command like nohup which will just call your script:

nohup python3 your_script.py

Now you can call these .sh files in your cron script to manage your schedule.

from crontab import CronTab
import os
import sys
cron = CronTab(user='sshuser')

job1 = cron.new(command="sh startup.sh")
job1.hour.on(5) # Mention your own time here
job1.minute.on(30)

job2 = cron.new(command="sh shutdown.sh")
job1.hour.on(6) # Mention your own time here
job1.minute.on(30)

for item in cron:
    print(item)
print(job1.enable())
cron.write()

Refer this to get some more context about cron and some more useful functions. https://pypi.org/project/python-crontab/

Sign up to request clarification or add additional context in comments.

6 Comments

Appreciate the answer, I keep my initial thoughts, I would rather add a new argument on the function than using cron.
You can do that but adding an argument for just scheduling ie for starting and killing a file is not correct. I guess you should keep the core logic and schedule logic separate, just an suggestion. Because in future if you require to change your logic of scheduling then you will need to add some more arguments which seems wrong.
And moreover if you plan on using this script for a long time I would suggest using an Azkaban or an Airflow (for scheduling ) for manageability.
With another argument I would not start and kill. I would handle it the same way I handle frame rate. Before putting a frame to the video recorder queue, I check whether the frame rate is correct. In the same manner I can only put frames for recorder to write if they belong within a "recording date + duration" interval. I am already deep in threads and scripts (processing fun also has threading inside). Scheduling through cron and not directly in main.py or camera.py will add yet another level of complexity I'm trying to avoid.
Yes, upvoted for modularity and a general way to handle scheduling from a script :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.