Skip to content

Commit 10f1559

Browse files
committed
Add installer, doctor, and udev setup
1 parent 40d709a commit 10f1559

5 files changed

Lines changed: 241 additions & 0 deletions

File tree

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ For the most stable out-of-the-box setup, use:
3131

3232
## Quick Start
3333

34+
Recommended:
35+
36+
```bash
37+
chmod +x install.sh
38+
./install.sh
39+
source venv/bin/activate
40+
python3 configure.py
41+
```
42+
43+
Manual:
44+
3445
```bash
3546
python3 -m venv venv
3647
source venv/bin/activate
@@ -44,6 +55,24 @@ Then:
4455
2. Select a theme
4556
3. Click `Save and run`
4657

58+
## First-Run Diagnostics
59+
60+
If the monitor is not detected or themes do not upload, run:
61+
62+
```bash
63+
python3 tools/smartmonitor-theme-manager.py doctor
64+
```
65+
66+
For Linux HID permissions, install the included udev rule:
67+
68+
```bash
69+
sudo cp tools/99-smartmonitor-hiddev.rules /etc/udev/rules.d/
70+
sudo udevadm control --reload-rules
71+
sudo udevadm trigger
72+
```
73+
74+
Then unplug and replug the monitor.
75+
4776
## Licensing
4877

4978
The original project is licensed under `GNU GPL v3`.

README_RU.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@
3131

3232
## Быстрый старт
3333

34+
Рекомендуемый вариант:
35+
36+
```bash
37+
chmod +x install.sh
38+
./install.sh
39+
source venv/bin/activate
40+
python3 configure.py
41+
```
42+
43+
Ручная установка:
44+
3445
```bash
3546
python3 -m venv venv
3647
source venv/bin/activate
@@ -44,6 +55,24 @@ python3 configure.py
4455
2. выбрать тему
4556
3. нажать `Save and run`
4657

58+
## Диагностика первого запуска
59+
60+
Если монитор не определяется или темы не загружаются, выполните:
61+
62+
```bash
63+
python3 tools/smartmonitor-theme-manager.py doctor
64+
```
65+
66+
Для Linux можно установить готовое `udev`-правило для доступа к `hidraw` без ручного `chmod`:
67+
68+
```bash
69+
sudo cp tools/99-smartmonitor-hiddev.rules /etc/udev/rules.d/
70+
sudo udevadm control --reload-rules
71+
sudo udevadm trigger
72+
```
73+
74+
После этого отключите и снова подключите монитор.
75+
4776
## Что изменено относительно оригинала
4877

4978
В форк добавлено:

install.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
cd "$ROOT_DIR"
6+
7+
PYTHON_BIN="${PYTHON_BIN:-python3}"
8+
VENV_DIR="${VENV_DIR:-venv}"
9+
10+
echo "turing-smart-screen-python-HIDdev installer"
11+
echo "==========================================="
12+
13+
if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then
14+
echo "Error: $PYTHON_BIN was not found." >&2
15+
exit 1
16+
fi
17+
18+
if [ ! -d "$VENV_DIR" ]; then
19+
echo "Creating virtual environment: $VENV_DIR"
20+
"$PYTHON_BIN" -m venv "$VENV_DIR"
21+
fi
22+
23+
echo "Installing Python requirements..."
24+
"$VENV_DIR/bin/python" -m pip install --upgrade pip
25+
"$VENV_DIR/bin/pip" install -r requirements.txt
26+
27+
echo
28+
echo "Optional HID permission setup"
29+
echo "-----------------------------"
30+
if [ -f "tools/99-smartmonitor-hiddev.rules" ]; then
31+
if command -v sudo >/dev/null 2>&1; then
32+
read -r -p "Install udev rule for SmartMonitor HID access? [y/N] " answer
33+
case "$answer" in
34+
[yY]|[yY][eE][sS])
35+
sudo cp tools/99-smartmonitor-hiddev.rules /etc/udev/rules.d/99-smartmonitor-hiddev.rules
36+
sudo udevadm control --reload-rules
37+
sudo udevadm trigger
38+
echo "udev rule installed. Replug the monitor before running the app."
39+
;;
40+
*)
41+
echo "Skipped udev rule installation."
42+
;;
43+
esac
44+
else
45+
echo "sudo not found; skipping udev rule installation."
46+
fi
47+
fi
48+
49+
echo
50+
echo "Running doctor..."
51+
"$VENV_DIR/bin/python" tools/smartmonitor-theme-manager.py doctor || true
52+
53+
echo
54+
echo "Install complete."
55+
echo "Start configuration with:"
56+
echo " source $VENV_DIR/bin/activate"
57+
echo " python3 configure.py"

tools/99-smartmonitor-hiddev.rules

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SmartMonitor HIDdev / Fuldho-style 3.5" HID screen
2+
# VID:PID observed for this device family: 0483:0065
3+
#
4+
# Install:
5+
# sudo cp tools/99-smartmonitor-hiddev.rules /etc/udev/rules.d/
6+
# sudo udevadm control --reload-rules
7+
# sudo udevadm trigger
8+
# unplug and replug the monitor
9+
10+
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="0065", MODE="0666", TAG+="uaccess"

tools/smartmonitor-theme-manager.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import argparse
55
import hashlib
6+
import os
67
import shutil
78
import sys
89
from datetime import datetime, timezone
@@ -30,6 +31,7 @@
3031
if (REPO_ROOT / "vendor" / "themefor3.5").is_dir()
3132
else REPO_ROOT / "vendor" / "themefor3.5"
3233
)
34+
SMARTMONITOR_VID_PID = "0483:0065"
3335

3436

3537
def _yaml():
@@ -322,6 +324,117 @@ def import_all_compiled_vendor_themes(vendor_root: Path):
322324
print(f" {name}: {error}")
323325

324326

327+
def _check_line(ok: bool, message: str, detail: str = "") -> bool:
328+
marker = "OK" if ok else "WARN"
329+
print(f"[{marker}] {message}")
330+
if detail and not ok:
331+
print(f" {detail}")
332+
return ok
333+
334+
335+
def _find_hidraw_candidates() -> list[Path]:
336+
candidates = []
337+
for path in sorted(Path("/dev").glob("hidraw*")):
338+
if path.exists():
339+
candidates.append(path)
340+
return candidates
341+
342+
343+
def _lsusb_contains_smartmonitor() -> bool | None:
344+
try:
345+
import subprocess
346+
347+
result = subprocess.run(
348+
["lsusb"],
349+
text=True,
350+
capture_output=True,
351+
timeout=3,
352+
check=False,
353+
)
354+
except Exception:
355+
return None
356+
return SMARTMONITOR_VID_PID.lower() in result.stdout.lower()
357+
358+
359+
def run_doctor():
360+
print("SmartMonitor HIDdev doctor")
361+
print("==========================")
362+
all_ok = True
363+
364+
all_ok &= _check_line(sys.version_info >= (3, 10), f"Python version: {sys.version.split()[0]}")
365+
all_ok &= _check_line(CONFIG_PATH.is_file(), f"config.yaml present: {CONFIG_PATH}")
366+
all_ok &= _check_line((REPO_ROOT / "requirements.txt").is_file(), "requirements.txt present")
367+
368+
try:
369+
import PIL # noqa: F401
370+
import psutil # noqa: F401
371+
import ruamel.yaml # noqa: F401
372+
deps_ok = True
373+
except ModuleNotFoundError as exc:
374+
deps_ok = False
375+
all_ok = False
376+
_check_line(False, "Python dependencies installed", f"Missing module: {exc.name}")
377+
else:
378+
_check_line(True, "Python dependencies installed")
379+
380+
config_ok = False
381+
active_theme = None
382+
if CONFIG_PATH.is_file() and deps_ok:
383+
try:
384+
config_data = read_config()
385+
display = config_data.get("display", {})
386+
revision = display.get("REVISION")
387+
active_theme = Path(display.get("SMARTMONITOR_HID_THEME_FILE", "") or "")
388+
config_ok = revision == "A_HID"
389+
all_ok &= _check_line(config_ok, f"display.REVISION = {revision!r}", "Expected 'A_HID' for this fork")
390+
except Exception as exc:
391+
all_ok = False
392+
_check_line(False, "config.yaml can be parsed", str(exc))
393+
394+
themes = list_installed_themes()
395+
all_ok &= _check_line(bool(themes), f"installed SmartMonitor themes: {len(themes)}")
396+
397+
if active_theme:
398+
if not active_theme.is_absolute():
399+
active_theme = REPO_ROOT / active_theme
400+
all_ok &= _check_line(active_theme.is_file(), f"active theme file exists: {active_theme}")
401+
402+
lsusb_state = _lsusb_contains_smartmonitor()
403+
if lsusb_state is None:
404+
_check_line(False, "lsusb check skipped", "Install usbutils if you want VID:PID detection")
405+
else:
406+
all_ok &= _check_line(
407+
lsusb_state,
408+
f"USB device {SMARTMONITOR_VID_PID} visible" if lsusb_state else f"USB device {SMARTMONITOR_VID_PID} not visible",
409+
"Connect/replug the SmartMonitor or check USB permissions.",
410+
)
411+
412+
hidraw_candidates = _find_hidraw_candidates()
413+
all_ok &= _check_line(bool(hidraw_candidates), f"hidraw devices visible: {', '.join(str(p) for p in hidraw_candidates) or 'none'}")
414+
if hidraw_candidates:
415+
readable = [path for path in hidraw_candidates if os.access(path, os.R_OK | os.W_OK)]
416+
if readable:
417+
_check_line(True, f"hidraw read/write permission: {', '.join(str(p) for p in readable)}")
418+
else:
419+
all_ok = False
420+
_check_line(
421+
False,
422+
"hidraw read/write permission",
423+
"Install the udev rule from tools/99-smartmonitor-hiddev.rules or run with adjusted permissions.",
424+
)
425+
426+
print()
427+
if all_ok:
428+
print("Doctor result: ready")
429+
else:
430+
print("Doctor result: attention needed")
431+
print("Recommended next steps:")
432+
print(" 1. Run ./install.sh")
433+
print(" 2. Replug the SmartMonitor")
434+
print(" 3. Run python3 tools/smartmonitor-theme-manager.py doctor")
435+
return 0 if all_ok else 1
436+
437+
325438
def main():
326439
parser = argparse.ArgumentParser(description="Manage vendor img.dat themes for the HID SmartMonitor")
327440
subparsers = parser.add_subparsers(dest="command", required=True)
@@ -332,6 +445,9 @@ def main():
332445
parser_current = subparsers.add_parser("current", help="Print active SmartMonitor theme file from config.yaml")
333446
parser_current.set_defaults(func=lambda args: print_current())
334447

448+
parser_doctor = subparsers.add_parser("doctor", help="Check installation, config, HID device, and theme setup")
449+
parser_doctor.set_defaults(func=lambda args: sys.exit(run_doctor()))
450+
335451
parser_vendor = subparsers.add_parser("vendor-list", help="List vendor theme directories found in unpacked app")
336452
parser_vendor.add_argument("--vendor-root", type=Path, default=DEFAULT_VENDOR_ROOT,
337453
help=f"Vendor theme root (default: {DEFAULT_VENDOR_ROOT})")

0 commit comments

Comments
 (0)