From 24ae1d801e795aacf87708a3ebdcbaf24c495af8 Mon Sep 17 00:00:00 2001 From: Andreas Boeckler Date: Thu, 22 Feb 2024 18:04:16 +0100 Subject: [PATCH 1/4] implemted taking snapshots via shellcommand example: [webcam canon] location: printer icon: enabled: False stream_url: /webcam/stream snapshot_url: cmd:/home/pi/bin/canoncaptureframe --- canoncaptureframe --- BASEFILE=${1%%.jpg} gphoto2 --quiet --capture-image-and-download --filename="$BASEFILE.%C" --force-overwrite rm -f "$BASEFILE.cr3" --- --- component/timelapse.py | 15 +++++++++++---- docs/configuration.md | 5 ++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/component/timelapse.py b/component/timelapse.py index f25138a..dafa235 100644 --- a/component/timelapse.py +++ b/component/timelapse.py @@ -248,7 +248,7 @@ def parseWebcamConfig(self, webcamconfig) -> None: rotation ) - if not self.config['snapshoturl'].startswith('http'): + if not self.config['snapshoturl'].startswith('http') and not self.config['snapshoturl'].startswith('cmd:'): if not self.config['snapshoturl'].startswith('/'): self.config['snapshoturl'] = "http://localhost/" + \ self.config['snapshoturl'] @@ -470,15 +470,22 @@ async def newframe(self) -> None: self.framecount += 1 framefile = "frame" + str(self.framecount).zfill(6) + ".jpg" - cmd = "wget " + options + self.config['snapshoturl'] \ - + " -O " + self.temp_dir + framefile + url = self.config['snapshoturl'] + waittime = 2. + if self.config['snapshoturl'].startswith('cmd:'): + cmdStart = self.config['snapshoturl'][4:] + cmd = cmdStart + " " + self.temp_dir + framefile + waittime = 10. + else: + cmd = "wget " + options + self.config['snapshoturl'] \ + + " -O " + self.temp_dir + framefile self.lastframefile = framefile logging.debug(f"cmd: {cmd}") shell_cmd: SCMDComp = self.server.lookup_component('shell_command') scmd = shell_cmd.build_shell_command(cmd, None) try: - cmdstatus = await scmd.run(timeout=2., verbose=False) + cmdstatus = await scmd.run(timeout=waittime, verbose=False) except Exception: logging.exception(f"Error running cmd '{cmd}'") diff --git a/docs/configuration.md b/docs/configuration.md index 0ead318..6ddaf2a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -95,9 +95,12 @@ use or render. This setting let you choose which camera should be used to take frames from. It depends on the 'webcam' namespace in the moonraker DB and uses the 'snapshoturl', 'flipX' and 'flipY' associated whith selected camera. Alternatively you can configure -'snapshoturl', 'flip_x' and 'flip_y' in the moonraker.conf if your frontend doesn't support the webcams +'snapshoturl', 'flip_x' and 'flip_y' in the moonraker.conf if your frontend doesn't support the webcams namespace of moonraker DB. +'snapshoturl' can be a shellcommand, when the value is prefixed with 'cmd:', eg. 'cmd:/home/pi/bin/canondslrtakeframe.sh'. +The first argument is the absolute frame-filenmae. + #### gcode_verbose 'true' enables or 'false' disables verbosity of the Macros From 9930ec6bd0e823fad93b965ca49a1457477a3f78 Mon Sep 17 00:00:00 2001 From: Andreas Boeckler Date: Sat, 24 Feb 2024 14:23:23 +0100 Subject: [PATCH 2/4] refractor implemented snapsho via timelapse config option example for DSLR via gphoto [timelapse] park_time: 0.6 snapshot_cmd: /home/pi/bin/gphoto2_capture.sh snapshot_cmd_check: /home/pi/bin/gphoto2_check.sh #optional use_snapshot_cmd: True --- component/timelapse.py | 43 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/component/timelapse.py b/component/timelapse.py index dafa235..a8e4529 100644 --- a/component/timelapse.py +++ b/component/timelapse.py @@ -48,6 +48,7 @@ def __init__(self, confighelper: ConfigHelper) -> None: self.byrendermacro = False self.hyperlapserunning = False self.printing = False + self.snapshotCmdWorking = False self.noWebcamDb = False self.confighelper = confighelper @@ -71,6 +72,10 @@ def __init__(self, confighelper: ConfigHelper) -> None: 'mode': "layermacro", 'camera': "", 'snapshoturl': "http://localhost:8080/?action=snapshot", + 'use_snapshot_cmd': False, + 'snapshot_cmd': '', + 'snapshot_cmd_check': '', + 'snapshot_cmd_waittime': 10.0, 'stream_delay_compensation': 0.05, 'gcode_verbose': False, 'parkhead': False, @@ -169,6 +174,8 @@ def __init__(self, confighelper: ConfigHelper) -> None: async def component_init(self) -> None: await self.getWebcamConfig() + if self.config['use_snapshot_cmd'] == True: + self.snapshotCmdWorking = await self.check_snapshot_cmd() def overwriteDbconfigWithConfighelper(self) -> None: blockedsettings = [] @@ -248,7 +255,7 @@ def parseWebcamConfig(self, webcamconfig) -> None: rotation ) - if not self.config['snapshoturl'].startswith('http') and not self.config['snapshoturl'].startswith('cmd:'): + if not self.config['snapshoturl'].startswith('http'): if not self.config['snapshoturl'].startswith('/'): self.config['snapshoturl'] = "http://localhost/" + \ self.config['snapshoturl'] @@ -460,6 +467,26 @@ async def stop_hyperlapse(self) -> None: logging.exception(msg) self.hyperlapserunning = False + async def check_snapshot_cmd(self) -> bool: + if self.config['snapshot_cmd'] == '': + return False + if self.config['snapshot_cmd_check'] == '': + return True + cmd = self.config['snapshot_cmd_check'] + shell_cmd: SCMDComp = self.server.lookup_component('shell_command') + scmd = shell_cmd.build_shell_command(cmd, None) + try: + cmdstatus = await scmd.run(timeout=2., verbose=False) + except Exception: + logging.exception(f"Error running cmd '{cmd}'") + return False + + logging.info(f"check_snapshot_cmd: {cmd} -> {cmdstatus}") + if cmdstatus: + return True + else: + return False + async def newframe(self) -> None: # make sure webcamconfig is uptodate before grabbing a new frame await self.getWebcamConfig() @@ -472,10 +499,12 @@ async def newframe(self) -> None: framefile = "frame" + str(self.framecount).zfill(6) + ".jpg" url = self.config['snapshoturl'] waittime = 2. - if self.config['snapshoturl'].startswith('cmd:'): - cmdStart = self.config['snapshoturl'][4:] - cmd = cmdStart + " " + self.temp_dir + framefile - waittime = 10. + if self.config['use_snapshot_cmd'] == True and not self.snapshotCmdWorking: + logging.info(f"snapshot_cmd_check failed on startup or snapshot_cmd is empty: {self.config['snapshot_cmd']}") + + if self.config['use_snapshot_cmd'] == True and self.snapshotCmdWorking: + cmd = self.config['snapshot_cmd'] + " " + self.temp_dir + framefile + waittime = self.config['snapshot_cmd_waittime'] else: cmd = "wget " + options + self.config['snapshoturl'] \ + " -O " + self.temp_dir + framefile @@ -519,6 +548,10 @@ async def handle_gcode_response(self, gresponse: str) -> None: # print_started self.cleanup() self.printing = True + self.snapshotCmdWorking = False + + if self.config['use_snapshot_cmd'] == True: + self.snapshotCmdWorking = await self.check_snapshot_cmd() # start hyperlapse if mode is set if self.config['mode'] == "hyperlapse": From 1e5c0c4d9556d9d38dfb752812522cad7bd85eab Mon Sep 17 00:00:00 2001 From: Andreas Boeckler Date: Sat, 24 Feb 2024 14:35:30 +0100 Subject: [PATCH 3/4] snapshot_cmd documentation --- docs/configuration.md | 16 ++++++++++++++-- scripts/gphoto2_capture.sh | 8 ++++++++ scripts/gphoto2_check.sh | 5 +++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100755 scripts/gphoto2_capture.sh create mode 100755 scripts/gphoto2_check.sh diff --git a/docs/configuration.md b/docs/configuration.md index 6ddaf2a..c149e87 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -98,8 +98,20 @@ It depends on the 'webcam' namespace in the moonraker DB and uses the 'snapshoturl', 'flip_x' and 'flip_y' in the moonraker.conf if your frontend doesn't support the webcams namespace of moonraker DB. -'snapshoturl' can be a shellcommand, when the value is prefixed with 'cmd:', eg. 'cmd:/home/pi/bin/canondslrtakeframe.sh'. -The first argument is the absolute frame-filenmae. +#### use_snapshot_cmd +'true' enables snapshot_cmd processing. + +#### snapshot_cmd +This defines which creates the snapshot. The +See scripts/gphoto2_capture.sh for an example + +#### snapshot_cmd_check' +This defines an optional testscript, which is run on start of the job. It checks if the camera is available. +If not, the normal webcam is used. + +#### snapshot_cmd_waittime +This defines the wait time for the snapshot to be created. +You should increase the 'park_time' setting for better results. #### gcode_verbose 'true' enables or 'false' disables verbosity of the Macros diff --git a/scripts/gphoto2_capture.sh b/scripts/gphoto2_capture.sh new file mode 100755 index 0000000..5decefb --- /dev/null +++ b/scripts/gphoto2_capture.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +BASEFILE=${1%%.jpg} + +# note: make sure that you're camera just creates small/medium jpg and no raws or +# you're raspberrypi will habe all lot of data to process + +gphoto2 --quiet --capture-image-and-download --filename="$BASEFILE.%C" --force-overwrite diff --git a/scripts/gphoto2_check.sh b/scripts/gphoto2_check.sh new file mode 100755 index 0000000..80c5ae4 --- /dev/null +++ b/scripts/gphoto2_check.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e +#fails if camera is not connected +exec gphoto2 --get-config /main/imgsettings/imageformat >& /dev/null From 8bfcee9b5807558c0592e420703a1263ac4776d2 Mon Sep 17 00:00:00 2001 From: Andreas Boeckler Date: Sat, 24 Feb 2024 14:57:11 +0100 Subject: [PATCH 4/4] code cleanup --- component/timelapse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component/timelapse.py b/component/timelapse.py index a8e4529..bbec25e 100644 --- a/component/timelapse.py +++ b/component/timelapse.py @@ -497,17 +497,17 @@ async def newframe(self) -> None: self.framecount += 1 framefile = "frame" + str(self.framecount).zfill(6) + ".jpg" - url = self.config['snapshoturl'] - waittime = 2. if self.config['use_snapshot_cmd'] == True and not self.snapshotCmdWorking: logging.info(f"snapshot_cmd_check failed on startup or snapshot_cmd is empty: {self.config['snapshot_cmd']}") + waittime = 2. if self.config['use_snapshot_cmd'] == True and self.snapshotCmdWorking: cmd = self.config['snapshot_cmd'] + " " + self.temp_dir + framefile waittime = self.config['snapshot_cmd_waittime'] else: cmd = "wget " + options + self.config['snapshoturl'] \ + " -O " + self.temp_dir + framefile + self.lastframefile = framefile logging.debug(f"cmd: {cmd}")