-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add screen capture functionality for TekScope device driver family (#342
) * feat: Added a screen capture mixin and implemented the functionality for the TekScope family of device drivers * refactor: Add code to ensure that the folder paths exist, both locally and on TekScope. Also added an example to the basic_usage.md file. * docs: Update docstrings to indicate some parameters aren't used in certain devices * refactor: Allow leaving the filename empty for saving a screenshot, it will now default to a timestamped filename
- Loading branch information
Showing
9 changed files
with
346 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
"""Save a screenshot on the device and copy it to the local machine/environment.""" | ||
|
||
from tm_devices import DeviceManager | ||
from tm_devices.drivers import MSO6B | ||
|
||
with DeviceManager(verbose=True) as dm: | ||
# Add a scope | ||
scope: MSO6B = dm.add_scope("192.168.1.5") | ||
|
||
# Send some commands | ||
scope.add_new_math("MATH1", "CH1") # add MATH1 to CH1 | ||
scope.turn_channel_on("CH2") # turn on channel 2 | ||
scope.set_and_check(":HORIZONTAL:SCALE", 100e-9) # adjust horizontal scale | ||
|
||
# Save a screenshot as a timestamped file. This will create a screenshot on the device, | ||
# copy it to the current working directory on the local machine, | ||
# and then delete the screenshot file from the device. | ||
scope.save_screenshot() | ||
|
||
# Save a screenshot as "example.png". This will create a screenshot on the device, | ||
# copy it to the current working directory on the local machine, | ||
# and then delete the screenshot file from the device. | ||
scope.save_screenshot("example.png") | ||
|
||
# Save a screenshot as "example.jpg". This will create a screenshot on the device | ||
# using INVERTED colors in the "./device_folder" folder, | ||
# copy it to "./images/example.jpg" on the local machine, | ||
# but this time the screenshot file on the device will not be deleted. | ||
scope.save_screenshot( | ||
"example.jpg", | ||
colors="INVERTED", | ||
local_folder="./images", | ||
device_folder="./device_folder", | ||
keep_device_file=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
src/tm_devices/driver_mixins/abstract_device_functionality/screen_capture_mixin.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
"""A mixin class providing common methods for devices that can perform screen captures.""" | ||
|
||
from __future__ import annotations | ||
|
||
from abc import ABC, abstractmethod | ||
from datetime import datetime | ||
from pathlib import Path | ||
from typing import final, Optional, Tuple, TYPE_CHECKING, Union | ||
|
||
from dateutil.tz import tzlocal | ||
|
||
if TYPE_CHECKING: | ||
import os | ||
|
||
|
||
class ScreenCaptureMixin(ABC): | ||
"""A mixin class providing common methods for devices that can perform screen captures.""" | ||
|
||
@property | ||
@abstractmethod | ||
def valid_image_extensions(self) -> Tuple[str, ...]: | ||
"""Return a tuple of valid image extensions for this device. | ||
The extensions will be in the format '.ext', where 'ext' is the lowercase extension, | ||
e.g. (".png", ".jpg"). | ||
Returns: | ||
Tuple[str, ...]: A tuple of valid, lowercase image extensions for this device. | ||
""" | ||
|
||
@final | ||
def save_screenshot( | ||
self, | ||
filename: Optional[Union[str, os.PathLike[str]]] = None, | ||
*, | ||
colors: Optional[str] = None, | ||
view_type: Optional[str] = None, | ||
local_folder: Union[str, os.PathLike[str]] = "./", | ||
device_folder: Union[str, os.PathLike[str]] = "./", | ||
keep_device_file: bool = False, | ||
) -> None: | ||
"""Capture a screenshot from the device and save it locally. | ||
Args: | ||
filename: The name of the file to save the screenshot as. Defaults to a timestamped | ||
name using the first valid image extension. | ||
colors: The color scheme to use for the screenshot. (Not used by all devices) | ||
view_type: The type of view to capture. (Not used by all devices) | ||
local_folder: The local folder to save the screenshot in. Defaults to "./". | ||
device_folder: The folder on the device to save the screenshot in. Defaults to "./". | ||
keep_device_file: Whether to keep the file on the device after downloading it. | ||
Defaults to False. | ||
""" | ||
if not filename: | ||
filename_path = Path( | ||
datetime.now(tz=tzlocal()).strftime( | ||
f"%Y%m%d_%H%M%S{self.valid_image_extensions[0]}" | ||
) | ||
) | ||
else: | ||
filename_path = Path(filename) | ||
if filename_path.suffix.lower() not in self.valid_image_extensions: | ||
msg = ( | ||
f"Invalid image extension: {filename_path.suffix!r}, " | ||
f"valid extensions are {self.valid_image_extensions!r}" | ||
) | ||
raise ValueError(msg) | ||
local_folder_path = Path(local_folder) | ||
device_folder_path = Path(device_folder) | ||
if local_folder_path.is_file() or local_folder_path.suffix: | ||
msg = f"Local folder path ({local_folder_path.as_posix()}) is a file, not a directory." | ||
raise ValueError(msg) | ||
if device_folder_path.is_file() or device_folder_path.suffix: | ||
msg = ( | ||
f"Device folder path ({device_folder_path.as_posix()}) is a file, not a directory." | ||
) | ||
raise ValueError(msg) | ||
if not local_folder_path.exists(): | ||
local_folder_path.mkdir(parents=True) | ||
self._save_screenshot( | ||
filename=filename_path, | ||
colors=colors, | ||
view_type=view_type, | ||
local_folder=Path(local_folder), | ||
device_folder=Path(device_folder), | ||
keep_device_file=keep_device_file, | ||
) | ||
|
||
@abstractmethod | ||
def _save_screenshot( | ||
self, | ||
filename: Path, | ||
*, | ||
colors: Optional[str], | ||
view_type: Optional[str], | ||
local_folder: Path, | ||
device_folder: Path, | ||
keep_device_file: bool = False, | ||
) -> None: | ||
"""Capture a screenshot from the device and save it locally. | ||
Args: | ||
filename: The name of the file to save the screenshot as. | ||
colors: The color scheme to use for the screenshot. | ||
view_type: The type of view to capture. | ||
local_folder: The local folder to save the screenshot in. Defaults to "./". | ||
device_folder: The folder on the device to save the screenshot in. Defaults to "./". | ||
keep_device_file: Whether to keep the file on the device after downloading it. | ||
Defaults to False. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.