-
Notifications
You must be signed in to change notification settings - Fork 20
Add automatic temperature sensor selection for daemon #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,14 +28,17 @@ | |
| [7] checksum | ||
| [8-63] 56 bytes Pixel data (RGB565) | ||
| """ | ||
| from __future__ import annotations | ||
|
|
||
| import math | ||
| import os | ||
| from typing import override | ||
| from typing import TYPE_CHECKING, override | ||
|
|
||
| import cv2 | ||
| import numpy as np | ||
| from PIL import Image | ||
|
|
||
| if TYPE_CHECKING: | ||
| from PIL import Image | ||
|
|
||
| from .EpomakerCommand import EpomakerCommand, CommandStructure, EpomakerStreamedCommand, IEpomakerCommand | ||
| from .data.constants import IMAGE_DIMENSIONS | ||
|
|
@@ -127,7 +130,12 @@ def prepare_gif(gif_path: str): | |
| return None, None, None | ||
|
|
||
| try: | ||
| gif = Image.open(gif_path) | ||
| from PIL import Image as PILImage | ||
|
|
||
| gif = PILImage.open(gif_path) | ||
| except ImportError: | ||
| Logger.log_error("GIF upload requires Pillow: install python-pillow or Pillow") | ||
| return None, None, None | ||
| except Exception as e: | ||
| Logger.log_error(f"Failed to open GIF: {e}") | ||
| return None, None, None | ||
|
|
@@ -218,7 +226,9 @@ def _extract_composited_frames(self, gif: Image.Image) -> list[Image.Image]: | |
| """ | ||
| step = self.step | ||
|
|
||
| canvas = Image.new("RGBA", gif.size, (0, 0, 0, 255)) | ||
| from PIL import Image as PILImage | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be moved to other imports to avoid code duplication |
||
|
|
||
| canvas = PILImage.new("RGBA", gif.size, (0, 0, 0, 255)) | ||
| frames: list[Image.Image] = [] | ||
|
|
||
| for i in range(self.n_frames): | ||
|
|
@@ -230,7 +240,7 @@ def _extract_composited_frames(self, gif: Image.Image) -> list[Image.Image]: | |
|
|
||
| disposal = gif.disposal_method if hasattr(gif, 'disposal_method') else 0 | ||
| if disposal == 2: | ||
| canvas = Image.new("RGBA", gif.size, (0, 0, 0, 255)) | ||
| canvas = PILImage.new("RGBA", gif.size, (0, 0, 0, 255)) | ||
|
|
||
| return frames | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,9 +65,7 @@ def __contains__(self, key: str) -> bool: | |
|
|
||
|
|
||
| def get_main_config_directory() -> Path: | ||
| home_dir = Path(os.path.abspath(os.curdir)) | ||
| config_dir = home_dir / CONFIG_DIRECTORY | ||
| return config_dir | ||
| return Path.home() / CONFIG_DIRECTORY | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better to leave previous functionality and not using home directory |
||
|
|
||
|
|
||
| def create_default_main_config(config_file: Path) -> None: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,8 @@ | |
| and provide a single point of project configuration | ||
| """ | ||
| import os | ||
| import tempfile | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| CONFIG_DIRECTORY = ".epomaker-controller" | ||
|
|
@@ -15,7 +17,7 @@ | |
| if not os.path.exists(ROOT_FOLDER): | ||
| os.mkdir(ROOT_FOLDER) | ||
|
|
||
| TMP_FOLDER = os.path.abspath("./.epomaker_controller") | ||
| TMP_FOLDER = os.path.join(tempfile.gettempdir(), "epomaker_controller") | ||
| ETC_FOLDER = os.path.abspath(ROOT_FOLDER + "etc/") | ||
|
|
||
| # Create folder on Windows | ||
|
|
@@ -29,6 +31,6 @@ | |
|
|
||
| RULE_FILE_PATH = ETC_FOLDER + "/udev/rules.d/99-epomaker-rt100.rules" | ||
| TMP_FILE_PATH = TMP_FOLDER + "/99-epomaker-rt100.rules" | ||
| PATH_TO_DEFAULT_CONFIG = "src/epomakercontroller/configs/default.json" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That could lead to errors when this file moved somewhere, I'd better leave it with path |
||
| PATH_TO_DEFAULT_CONFIG = Path(__file__).with_name("default.json") | ||
|
|
||
| DAEMON_TIME_DELAY = 1.6 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| from epomakercontroller.utils.sensors import select_temp_device | ||
|
|
||
|
|
||
| def test_select_temp_device_prefers_cpu_sensor() -> None: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use |
||
| temps = { | ||
| "NVIDIA-GPU-0": 70.0, | ||
| "coretemp-0": 52.0, | ||
| "coretemp-1": 55.0, | ||
| } | ||
|
|
||
| assert select_temp_device(temps) == "coretemp-1" | ||
|
|
||
|
|
||
| def test_select_temp_device_uses_generic_sensor_before_gpu() -> None: | ||
| temps = { | ||
| "NVIDIA-GPU-0": 70.0, | ||
| "nvme-0": 44.0, | ||
| } | ||
|
|
||
| assert select_temp_device(temps) == "nvme-0" | ||
|
|
||
|
|
||
| def test_select_temp_device_falls_back_to_gpu() -> None: | ||
| temps = { | ||
| "NVIDIA-GPU-0": 70.0, | ||
| "NVIDIA-GPU-1": 72.0, | ||
| } | ||
|
|
||
| assert select_temp_device(temps) == "NVIDIA-GPU-1" | ||
|
|
||
|
|
||
| def test_select_temp_device_returns_none_without_sensors() -> None: | ||
| assert select_temp_device({}) is None | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it here and not with other imports?