Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
---
config:
# Configuration values to set up basic communication
# Set your COM port e.g. COM3 for Windows, /dev/ttyACM0 for Linux...
# Use AUTO for COM port auto-discovery (may not work on every setup)
# COM_PORT: "/dev/ttyACM0"
# COM_PORT: "COM3"
COM_PORT: "AUTO"
COM_PORT: AUTO

# Theme to use (located in res/themes)
# Use the name of the folder as value
# Choose a theme made for your screen size (see DISPLAY_SIZE inside theme.yaml)
THEME: 3.5inchTheme2
THEME: Gradient

# Hardware sensors reading
# Choose the appropriate method for reading your hardware sensors:
# - PYTHON use Python libraries (psutils, GPUtil...) to read hardware sensors (supports all OS but not all HW)
# - LHM use LibreHardwareMonitor library to read hardware sensors (Windows only - NEEDS ADMIN RIGHTS)
# - STUB / STATIC use random/static data instead of real hardware sensors
# - AUTO use the best method based on your OS: Windows OS will use LHM, other OS will use Python libraries
HW_SENSORS: AUTO
HW_SENSORS: PYTHON

# Network interfaces
# Linux/MacOS interfaces are named "eth0", "wlan0", "wlp1s0", "enp2s0"...
# For Windows use the interfaces pretty name: "Ethernet 2", "Wi-Fi", ...
# Leave the fields empty if the card does not exist on your setup
ETH: "" # Ethernet Card
WLO: "" # Wi-Fi Card
ETH: Ethernet # Ethernet Card
WLO: '' # Wi-Fi Card

# CPU fan
# For Linux/MacOS platforms, the CPU fan is amongst all fan sensors gathered from the motherboard chipset
Expand All @@ -41,14 +40,14 @@ config:

# OpenWeatherMap API KEY. Can be obtained by creating a free account on https://home.openweathermap.org/users/sign_up.
# You need to subscribe to the 3.0 OneCallAPI that has 1000 free daily calls
WEATHER_API_KEY: ""
WEATHER_API_KEY: ''
# Location from which to display the weather. Use for example https://www.latlong.net/ to get latitude/longitude
WEATHER_LATITUDE: 45.75
WEATHER_LONGITUDE: 4.85
WEATHER_LATITUDE: '45.75'
WEATHER_LONGITUDE: '4.85'
# Units used to display temperatures (metric - °C, imperial - °F, standard - °K)
WEATHER_UNITS: metric
# Language is used by the API. Find more here https://openweathermap.org/api/one-call-3#multi
WEATHER_LANGUAGE: en
WEATHER_LANGUAGE: de

display:
# Display revision:
Expand All @@ -60,7 +59,7 @@ display:
# - WEACT_B for WeAct Studio Display FS V1 0.96"
# - SIMU for simulated display (image written in screencap.png). Width & height will be detected from the theme
# To identify your smart screen: https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions
REVISION: A
REVISION: C_USB

# Display Brightness
# Set this as the desired %, 0 being completely dark and 100 being max brightness
Expand Down
77 changes: 52 additions & 25 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@
SIZE_3_5_INCH = "3.5\""
SIZE_5_INCH = "5\""
SIZE_8_8_INCH = "8.8\""
SIZE_8_8_INCH_USB = "8.8\" (V1.1) or 9.2\""
SIZE_2_1_INCH = "2.1\"" # Only for retro compatibility
SIZE_2_x_INCH = "2.1\" / 2.8\""
SIZE_0_96_INCH = "0.96\""

size_list = (SIZE_0_96_INCH, SIZE_2_x_INCH, SIZE_3_5_INCH, SIZE_5_INCH, SIZE_8_8_INCH)
size_list = (SIZE_0_96_INCH, SIZE_2_x_INCH, SIZE_3_5_INCH, SIZE_5_INCH, SIZE_8_8_INCH, SIZE_8_8_INCH_USB)

# Maps between config.yaml values and GUI description
revision_and_size_to_model_map = {
Expand All @@ -80,6 +81,7 @@
('C', SIZE_2_x_INCH): TURING_MODEL,
('C', SIZE_5_INCH): TURING_MODEL,
('C', SIZE_8_8_INCH): TURING_MODEL,
('C_USB', SIZE_8_8_INCH_USB): TURING_MODEL,
('D', SIZE_3_5_INCH): KIPYE_MODEL,
('WEACT_A', SIZE_3_5_INCH): WEACT_MODEL,
('WEACT_B', SIZE_0_96_INCH): WEACT_MODEL,
Expand All @@ -97,6 +99,7 @@
(TURING_MODEL, SIZE_2_x_INCH): 'C',
(TURING_MODEL, SIZE_5_INCH): 'C',
(TURING_MODEL, SIZE_8_8_INCH): 'C',
(TURING_MODEL, SIZE_8_8_INCH_USB): 'C_USB',
(KIPYE_MODEL, SIZE_3_5_INCH): 'D',
(WEACT_MODEL, SIZE_3_5_INCH): 'WEACT_A',
(WEACT_MODEL, SIZE_0_96_INCH): 'WEACT_B',
Expand All @@ -121,20 +124,20 @@
"sk": "Slovak", "sl": "Slovenian", "sp": "Spanish", "sv": "Swedish", "th": "Thai", "tr": "Turkish",
"ua": "Ukrainian", "vi": "Vietnamese", "zu": "Zulu"}

MAIN_DIRECTORY = str(Path(__file__).parent.resolve()) + "/"
THEMES_DIR = MAIN_DIRECTORY + 'res/themes'
MAIN_DIRECTORY = Path(__file__).resolve().parent
THEMES_DIR = MAIN_DIRECTORY / "res/themes"

circular_mask = Image.open(MAIN_DIRECTORY + "res/backgrounds/circular-mask.png")

circular_mask = Image.open(MAIN_DIRECTORY / "res/backgrounds/circular-mask.png")

def get_theme_data(name: str):
dir = os.path.join(THEMES_DIR, name)
dir = THEMES_DIR / name

# checking if it is a directory
if os.path.isdir(dir):
# Check if a theme.yaml file exists
theme = os.path.join(dir, 'theme.yaml')
if os.path.isfile(theme):
# Get display size from theme.yaml
with open(theme, "rt", encoding='utf8') as stream:
if dir.is_dir():
theme = dir / "theme.yaml"
if theme.is_file():
with open(theme, "rt", encoding="utf8") as stream:
theme_data, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(stream)
return theme_data
return None
Expand Down Expand Up @@ -186,8 +189,7 @@ def __init__(self):
self.window = Tk()
self.window.title('Turing System Monitor configuration')
self.window.geometry("820x580")
self.window.iconphoto(True, PhotoImage(file=MAIN_DIRECTORY + "res/icons/monitor-icon-17865/64.png"))
# When window gets focus again, reload theme preview in case it has been updated by theme editor
self.window.iconphoto(True,PhotoImage(file=str(MAIN_DIRECTORY / "res/icons/monitor-icon-17865/64.png"))) # When window gets focus again, reload theme preview in case it has been updated by theme editor
self.window.bind("<FocusIn>", self.on_theme_change)
self.window.after(0, self.on_fan_speed_update)

Expand Down Expand Up @@ -310,14 +312,17 @@ def run(self):
def load_theme_preview(self):
theme_data = get_theme_data(self.theme_cb.get())

if theme_data and theme_data['display'].get("DISPLAY_SIZE", '3.5"') == SIZE_2_1_INCH:
theme_preview.paste(circular_mask, mask=circular_mask)

try:
theme_preview = Image.open(MAIN_DIRECTORY + "res/themes/" + self.theme_cb.get() + "/preview.png")
theme_preview = Image.open(MAIN_DIRECTORY / "res" / "themes" / self.theme_cb.get() / "preview.png")

if theme_data['display'].get("DISPLAY_SIZE", '3.5"') == SIZE_2_1_INCH:
# This is a circular screen: apply a circle mask over the preview
theme_preview.paste(circular_mask, mask=circular_mask)
except:
theme_preview = Image.open(MAIN_DIRECTORY + "res/docs/no-preview.png")
theme_preview = Image.open(MAIN_DIRECTORY / "res/docs/no-preview.png")
finally:
theme_preview.thumbnail((320, 480), Image.Resampling.LANCZOS)
self.theme_preview_img = ImageTk.PhotoImage(theme_preview)
Expand All @@ -335,7 +340,7 @@ def load_theme_preview(self):
self.theme_author.place(x=10, y=self.theme_preview_img.height() + 15)

def load_config_values(self):
with open(MAIN_DIRECTORY + "config.yaml", "rt", encoding='utf8') as stream:
with open(MAIN_DIRECTORY / "config.yaml", "rt", encoding='utf8') as stream:
self.config, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(stream)

# Check if theme is valid
Expand Down Expand Up @@ -383,6 +388,8 @@ def load_config_values(self):
size = get_theme_size(self.config['config']['THEME'])
size = size.replace(SIZE_2_1_INCH, SIZE_2_x_INCH) # If a theme is for 2.1" then it also is for 2.8"
try:
if size == SIZE_8_8_INCH and self.config['display']['REVISION'] == 'C_USB':
size = SIZE_8_8_INCH_USB
self.size_cb.set(size)
except:
self.size_cb.current(0)
Expand Down Expand Up @@ -445,7 +452,7 @@ def save_config_values(self):
self.config['display']['DISPLAY_REVERSE'] = [k for k, v in reverse_map.items() if v == self.orient_cb.get()][0]
self.config['display']['BRIGHTNESS'] = int(self.brightness_slider.get())

with open(MAIN_DIRECTORY + "config.yaml", "w", encoding='utf-8') as file:
with open(MAIN_DIRECTORY / "config.yaml", "w", encoding='utf-8') as file:
ruamel.yaml.YAML().dump(self.config, file)

def save_additional_config(self, ping: str, api_key: str, lat: str, long: str, unit: str, lang: str):
Expand All @@ -456,7 +463,7 @@ def save_additional_config(self, ping: str, api_key: str, lat: str, long: str, u
self.config['config']['WEATHER_UNITS'] = unit
self.config['config']['WEATHER_LANGUAGE'] = lang

with open(MAIN_DIRECTORY + "config.yaml", "w", encoding='utf-8') as file:
with open(MAIN_DIRECTORY / "config.yaml", "w", encoding='utf-8') as file:
ruamel.yaml.YAML().dump(self.config, file)

def on_theme_change(self, e=None):
Expand All @@ -466,25 +473,44 @@ def on_weatherping_click(self):
self.more_config_window.show()

def on_open_theme_folder_click(self):
path = f'"{MAIN_DIRECTORY}res/themes"'
#path = f'"{MAIN_DIRECTORY}res/themes"'
#if platform.system() == "Windows":
# os.startfile(path)
#elif platform.system() == "Darwin":
# subprocess.Popen(["open", path])
#else:
# subprocess.Popen(["xdg-open", path])
path = MAIN_DIRECTORY / "res/themes"

if platform.system() == "Windows":
os.startfile(path)
elif platform.system() == "Darwin":
subprocess.Popen(["open", path])
subprocess.Popen(["open", str(path)])
else:
subprocess.Popen(["xdg-open", path])
subprocess.Popen(["xdg-open", str(path)])


def on_theme_editor_click(self):
subprocess.Popen(
f'"{MAIN_DIRECTORY}{glob.glob("theme-editor.*", root_dir=MAIN_DIRECTORY)[0]}" "{self.theme_cb.get()}"',
shell=True)
theme_editor = next(MAIN_DIRECTORY.glob("theme-editor.*"))

if platform.system() == "Windows":
subprocess.Popen([str(theme_editor), self.theme_cb.get()], shell=True)
else:
subprocess.Popen([str(theme_editor), self.theme_cb.get()])


def on_save_click(self):
self.save_config_values()

def on_saverun_click(self):
self.save_config_values()
subprocess.Popen(f'"{MAIN_DIRECTORY}{glob.glob("main.*", root_dir=MAIN_DIRECTORY)[0]}"', shell=True)
main_file = next(MAIN_DIRECTORY.glob("main.*"))

if platform.system() == "Windows":
subprocess.Popen([str(main_file)], shell=True)
else:
subprocess.Popen([str(main_file)])

self.window.destroy()

def on_brightness_change(self, e=None):
Expand All @@ -508,6 +534,7 @@ def on_model_change(self, e=None):
def on_size_change(self, e=None):
size = self.size_cb.get()
size = size.replace(SIZE_2_x_INCH, SIZE_2_1_INCH) # For '2.1" / 2.8"' size, keep '2.1"' as size to get themes for
size = size.replace(SIZE_8_8_INCH_USB, SIZE_8_8_INCH)
themes = get_themes(size)
self.theme_cb.config(values=themes)

Expand Down
4 changes: 4 additions & 0 deletions library/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from library.lcd.lcd_comm_rev_a import LcdCommRevA
from library.lcd.lcd_comm_rev_b import LcdCommRevB
from library.lcd.lcd_comm_rev_c import LcdCommRevC
from library.lcd.lcd_comm_turing_usb import LcdCommTuringUSB
from library.lcd.lcd_comm_rev_d import LcdCommRevD
from library.lcd.lcd_comm_weact_a import LcdCommWeActA
from library.lcd.lcd_comm_weact_b import LcdCommWeActB
Expand Down Expand Up @@ -85,6 +86,9 @@ def __init__(self):
# Because of issue with Turing rev. C size auto-detection, manually configure screen width/height from theme
self.lcd = LcdCommRevC(com_port=config.CONFIG_DATA['config']['COM_PORT'],
update_queue=config.update_queue, display_width=width, display_height=height)
elif config.CONFIG_DATA["display"]["REVISION"] == "C_USB":
# On all USB models, manually configure screen width/height from theme
self.lcd = LcdCommTuringUSB(display_width=width, display_height=height)
elif config.CONFIG_DATA["display"]["REVISION"] == "D":
self.lcd = LcdCommRevD(com_port=config.CONFIG_DATA['config']['COM_PORT'],
update_queue=config.update_queue)
Expand Down
3 changes: 2 additions & 1 deletion library/lcd/lcd_comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__(self, com_port: str = "AUTO", display_width: int = 320, display_hei
self.lcd_serial = None

# String containing absolute path to serial port e.g. "COM3", "/dev/ttyACM1" or "AUTO" for auto-discovery
# Ignored for USB HID screens
self.com_port = com_port

# Display always start in portrait orientation by default
Expand Down Expand Up @@ -180,8 +181,8 @@ def ReadData(self, readSize: int):
return self.serial_read(readSize)

@staticmethod
@abstractmethod
def auto_detect_com_port() -> Optional[str]:
# To implement only for screens that use serial commands
pass

@abstractmethod
Expand Down
Loading
Loading