Skip to content

Commit

Permalink
Merge pull request #33 from mathoudebine/feature/system-monitor
Browse files Browse the repository at this point in the history
Release 2.0.0: system monitor
  • Loading branch information
mathoudebine authored Aug 31, 2022
2 parents 8477dfd + f374841 commit b661387
Show file tree
Hide file tree
Showing 97 changed files with 2,818 additions and 662 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,6 @@ dmypy.json

# PyCharm
.idea/

# Git mergetool backup
*.orig
72 changes: 42 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
# turing-smart-screen-python

| Check out new version with system monitoring features! |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Are you using your Turing Smart Screen for system monitoring? <br>If so, check out the new [**pre-release 2.0.0 beta 1 - 📊 System Monitor**](https://github.com/mathoudebine/turing-smart-screen-python/releases/tag/2.0.0-beta.1) or the `feature/system-monitoring` branch! <br><img src="res/pics/Theme3.5Inch.jpg" height="600" /> <img src="res/pics/ThemeTerminal.jpg" height="600" /> <br>It contains embedded hardware monitoring functions, theme creation from configuration files, serial port auto-detection... <br>See Release Notes to learn more about features and current limitations <br>_Python knowledges recommended._ |

---

### ⚠️ DISCLAIMER - PLEASE READ ⚠️

This project is **not affiliated, associated, authorized, endorsed by, or in any way officially connected with Turing brand**, or any of its subsidiaries, affiliates, manufacturers or sellers of the Turing products. All product and company names are the registered trademarks of their original owners.
Expand All @@ -14,42 +8,60 @@ This project is an open-source alternative software, not the USBMonitor.exe orig

---

A simple Python manager for "Turing Smart Screen" 3.5" IPS USB-C (UART) display, also known as :
A Python system monitor program and a library for "Turing Smart Screen" 3.5" IPS USB-C (UART) display, also known as :
- Turing USB35INCHIPS / USB35INCHIPSV2 (revision A)
- XuanFang display (revision B & flagship)
- [3.5 Inch 320*480 Mini Capacitive Touch Screen IPS Module](https://www.aliexpress.com/item/1005003723773653.html)

## Hardware
<img src="res/pics/smart-screen-3.webp" width="500"/>
<img src="res/docs/smart-screen-2.webp" height="300" />

[**Display hardware revisions supported: A, B & flagship**](https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions).
Flagship backplate RGB LEDs are also supported!

Operating systems supported : macOS, Windows, Linux (incl. Raspberry Pi) and all OS that support Python 3.x


## How to use

The Turing Smart Screen is a 3.5" USB-C display that shows as a serial port once connected.
It cannot be seen by the operating system as a monitor but pictures can be displayed on it.
### [> Follow instructions on the wiki to configure and start this project.](https://github.com/mathoudebine/turing-smart-screen-python/wiki)

There is 3 hardware revisions of the screen: [how to identify my version?](https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions) Version B and "flagship" use the same protocol.
A [Windows-only software is available](https://github.com/mathoudebine/turing-smart-screen-python/wiki/Vendor-apps) is provided by the vendor to manage this display.
This software allows creating themes to display your computer sensors on the screen, but does not offer a simple way to display custom pictures or text.
There are 2 possible uses of this project Python code:
* **[as a System Monitor](#system-monitor)**, a standalone program working with themes to display your computer HW info.
* **[integrated in your project](#control-the-display-from-your-python-projects)**, to control the display from your own Python code.

## Features
This Python script can do some simple operations on the Turing display like :
## System monitor

This project is mainly a complete standalone program to use your screen as a system monitor, like the original vendor app.
Some themes are already included for a quick start!
### [> Configure and start system monitor](https://github.com/mathoudebine/turing-smart-screen-python/wiki/System-monitor-:-how-to-start)
* Fully functional multi-OS code base (operates out of the box, tested on Windows, Linux & MacOS).
* Display configuration using `config.yaml` file: no Python code to edit.
* Support for all [3 screen HW revisions: A, B & flagship](https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions). Flagship backplate RGB LEDs are also supported!
* Support [multiple hardware sensors and metrics (CPU/GPU usage, temperatures, memory, disks, etc)](https://github.com/mathoudebine/turing-smart-screen-python/wiki/System-monitor-:-themes#stats-entry) with configurable refresh intervals.
* Allow [creation of themes (see `res/themes`) with `theme.yaml` files](https://github.com/mathoudebine/turing-smart-screen-python/wiki/System-monitor-:-themes) to be shared with the community!
* Easy to expand: additional code that pulls specific information can be written in a modular way without impacting existing code.
* Auto detect comm port. No longer need to hard set it, or if it changes on you then the config is wrong.

Screenshots from the latest version using included themes:
<img src="res/docs/Theme3.5Inch.jpg" height="400" /> <img src="res/docs/ThemeTerminal.jpg" height="400" />

### [> Themes creation/edition](https://github.com/mathoudebine/turing-smart-screen-python/wiki/System-monitor-:-themes)

## Control the display from your Python projects

If you don't want to use your screen for system monitoring, you can just use this project as a module to do some simple operations on the display from any Python code :
- **Display custom picture**
- **Display text**
- **Display progress bar**
- **Screen rotation**
- Clear the screen (blank) - HW version A only
- Turn the screen on/off - HW version A only
- Display soft reset - HW version A only
- Clear the screen (blank)
- Turn the screen on/off
- Display soft reset
- Set brightness
- Set backplate RGB LEDs color (on supported hardware rev.)

Check `simple-program.py` as an example.

Operating systems supported : macOS, Windows, Linux (incl. Raspberry Pi) and all OS that support Python3.7
### [> Control the display from your code](Control-screen-from-your-own-code)

## Getting started
_Python knowledges recommended._
Download this project by cloning it or using the [Releases sections](https://github.com/mathoudebine/turing-smart-screen-python/releases)
Download and install the latest Python 3.x (min. 3.7) for your OS: https://www.python.org/downloads/
Plug your Turing display to your computer (install the drivers if on Windows)
[Identify your hardware revision (version A or version B/flagship)](https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions)
Open the `mainVersionA.py` or `mainVersionB.py` file and edit the [`COM_PORT`](https://github.com/mathoudebine/turing-smart-screen-python/blob/deb0a60b772f2c5acef377f13b959632ca649f9f/main.py#L15) variable to the port used by the display
Open a terminal and run `python3 mainVersionA.py / mainVersionB.py` or `py -3 mainVersionA.py / mainVersionB.py` depending on your OS
You should see animated content on your Turing display!

You can then edit the `mainVersionA.py / mainVersionB.py` file to change the content displayed, or use this file as a Python module for your personal Python project
27 changes: 27 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
config:
# Configuration values to set up basic communication
# Set your COM port e.g. COM3 for Windows, /dev/ttyACM0 for Linux...
# COM_PORT: "/dev/ttyACM0"
# COM_PORT: "COM3"
COM_PORT: "AUTO"

# Theme to use (located in res/themes)
# THEME: Terminal_theme
# THEME: Landscape6Grid
THEME: 3.5inchTheme2_theme

display:
# Display resolution in portrait orientation
# Do not use this setting to rotate display! Display orientation is managed by themes
DISPLAY_WIDTH: 320
DISPLAY_HEIGHT: 480

# Display Brightness
# Set this as the desired %, 0 being completely dark and 100 being max brightness
# Warning: screen can get very hot at high brightness!
BRIGHTNESS: 20

# Display revision: A or B (for "flagship" version, use B)
# To identify your revision: https://github.com/mathoudebine/turing-smart-screen-python/wiki/Hardware-revisions
REVISION: A
32 changes: 32 additions & 0 deletions library/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os
import queue
import sys

import yaml

from library.log import logger


def load_yaml(configfile):
with open(configfile, "r") as stream:
yamlconfig = yaml.safe_load(stream)
return yamlconfig


PATH = sys.path[0]
CONFIG_DATA = load_yaml("config.yaml")

try:
theme_path = "res/themes/" + CONFIG_DATA['config']['THEME'] + "/"
logger.info("Loading theme %s from %s" % (CONFIG_DATA['config']['THEME'], theme_path + "theme.yaml"))
THEME_DATA = load_yaml(theme_path + "theme.yaml")
THEME_DATA['PATH'] = theme_path
except:
logger.error("Theme not found or contains errors!")
try:
sys.exit(0)
except:
os._exit(0)

# Queue containing the serial requests to send to the screen
update_queue = queue.Queue()
93 changes: 93 additions & 0 deletions library/display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from library import config
from library.lcd_comm import Orientation
from library.lcd_comm_rev_a import LcdCommRevA
from library.lcd_comm_rev_b import LcdCommRevB
from library.log import logger

THEME_DATA = config.THEME_DATA
CONFIG_DATA = config.CONFIG_DATA


def _get_full_path(path, name):
if name:
return path + name
else:
return None


def _get_theme_orientation() -> Orientation:
if THEME_DATA["display"]["DISPLAY_ORIENTATION"] == 'portrait':
return Orientation.PORTRAIT
elif THEME_DATA["display"]["DISPLAY_ORIENTATION"] == 'landscape':
return Orientation.LANDSCAPE
elif THEME_DATA["display"]["DISPLAY_ORIENTATION"] == 'reverse_portrait':
return Orientation.REVERSE_PORTRAIT
elif THEME_DATA["display"]["DISPLAY_ORIENTATION"] == 'reverse_landscape':
return Orientation.REVERSE_LANDSCAPE
else:
logger.warning("Orientation '", THEME_DATA["display"]["DISPLAY_ORIENTATION"], "' unknown, using portrait")
return Orientation.PORTRAIT


class Display:
def __init__(self):
self.lcd = None
if CONFIG_DATA["display"]["REVISION"] == "A":
self.lcd = LcdCommRevA(com_port=CONFIG_DATA['config']['COM_PORT'],
display_width=CONFIG_DATA["display"]["DISPLAY_WIDTH"],
display_height=CONFIG_DATA["display"]["DISPLAY_HEIGHT"],
update_queue=config.update_queue)
elif CONFIG_DATA["display"]["REVISION"] == "B":
self.lcd = LcdCommRevB(com_port=CONFIG_DATA['config']['COM_PORT'],
display_width=CONFIG_DATA["display"]["DISPLAY_WIDTH"],
display_height=CONFIG_DATA["display"]["DISPLAY_HEIGHT"],
update_queue=config.update_queue)
else:
logger.error("Unknown display revision '", CONFIG_DATA["display"]["REVISION"], "'")

def initialize_display(self):
# Reset screen in case it was in an unstable state (screen is also cleared)
self.lcd.Reset()

# Send initialization commands
self.lcd.InitializeComm()

# Set brightness
self.lcd.SetBrightness(CONFIG_DATA["display"]["BRIGHTNESS"])

# Set backplate RGB LED color (for supported HW only)
self.lcd.SetBackplateLedColor(THEME_DATA['display']["DISPLAY_RGB_LED"])

# Set orientation
self.lcd.SetOrientation(_get_theme_orientation())

def display_static_images(self):
if THEME_DATA['static_images']:
for image in THEME_DATA['static_images']:
logger.debug(f"Drawing Image: {image}")
self.lcd.DisplayBitmap(
bitmap_path=THEME_DATA['PATH'] + THEME_DATA['static_images'][image].get("PATH"),
x=THEME_DATA['static_images'][image].get("X", 0),
y=THEME_DATA['static_images'][image].get("Y", 0),
width=THEME_DATA['static_images'][image].get("WIDTH", 0),
height=THEME_DATA['static_images'][image].get("HEIGHT", 0)
)

def display_static_text(self):
if THEME_DATA['static_text']:
for text in THEME_DATA['static_text']:
logger.debug(f"Drawing Text: {text}")
self.lcd.DisplayText(
text=THEME_DATA['static_text'][text].get("TEXT"),
x=THEME_DATA['static_text'][text].get("X", 0),
y=THEME_DATA['static_text'][text].get("Y", 0),
font=THEME_DATA['static_text'][text].get("FONT", "roboto-mono/RobotoMono-Regular.ttf"),
font_size=THEME_DATA['static_text'][text].get("FONT_SIZE", 10),
font_color=THEME_DATA['static_text'][text].get("FONT_COLOR", (0, 0, 0)),
background_color=THEME_DATA['static_text'][text].get("BACKGROUND_COLOR", (255, 255, 255)),
background_image=_get_full_path(THEME_DATA['PATH'],
THEME_DATA['static_text'][text].get("BACKGROUND_IMAGE", None))
)


display = Display()
Loading

0 comments on commit b661387

Please sign in to comment.