A small Windows tray app to control the brightness of Samsung Smart Monitors / TVs (tested idea: Odyssey G95SC-class devices) over your local network, written in Python + PyQt6.
It lives in the system tray, and when you click it, you get a clean brightness slider pop‑up. Under the hood it talks to the monitor using Samsung SmartThings TV WebSocket API via samsungtvws.
⚠️ This project is not an official Samsung app.
🧩 System tray app
- Runs in the background (no main window).
- Tray icon menu: Restart / Exit.
🎚️ Brightness slider pop-up
- Small popup window with a horizontal slider (0 → 50).
- Remembers last brightness value and restores it on next run.
📡 Network control via samsungtvws
- Sends remote-control key presses (MENU / arrows / ENTER / RETURN) to reach the brightness menu and adjust it.
🔐 Token / “Allow” handling
- First setup requests permission on the monitor (you’ll see Allow / Deny prompt on the screen).
- Token gets saved to disk so next runs are seamless.
🧠 First-run setup dialog
- Collects Monitor Name + Monitor IP.
- Saves config to
%APPDATA%\MonitorControl\app_config.json.
♻️ Auto reconnect
- If connection drops while sending a key, the app retries by reconnecting.
🧰 Logging
- Logs to stdout (when available) and to:
%APPDATA%\MonitorControl\app.log
Samsung monitors/TVs expose a remote-control style interface over the network.
This app does NOT set brightness directly by a numeric API call. Instead, it:
- Opens the monitor’s on-screen menu.
- Navigates to the brightness section.
- Sends LEFT/RIGHT key presses to change the value.
That’s why you may see the on-screen menu briefly when using the slider.
- Installer:
- Download the latest installer from GitHub Releases.
- Run it.
- At the end, the installer starts the app in setup mode.
- The app will ask for:
- Monitor Name (any label you want)
- Monitor IP (local IP of the monitor)
- Then you’ll see a permission prompt on the monitor: ✅ Choose Allow
After that, the tray icon should appear. Click the tray icon to open the slider.
If your installer creates an autostart shortcut, it will run on Windows boot.
Requirements:
- Windows 11
- Python 3.13.x
- VS Code (optional)
Open PowerShell in the project folder:
py -3.13 -m venv .venv
.\.venv\Scripts\activate
pip install -U pip
pip install -r requirements.txt
python Monitorcontrol.py
Your project uses onedir mode and no console.
Typical command style (adjust if you use a .spec): pyinstaller --noconsole --onedir --icon icon.ico Monitorcontrol.py
If you use a spec file, build with: pyinstaller Monitorcontrol.spec
Important notes:
samsungtvwsmay requirewebsocketsand PyInstaller might not detect it automatically.- If you hit:
ModuleNotFoundError: No module named 'websockets'add hiddenimports forwebsockets(or install it explicitly and ensure it is included).
- Use your
installer.issto package the whole onedir folder. - Recommended behavior:
- Copy the entire onedir output folder to Program Files
- Create Start Menu shortcut
- Create Startup shortcut (optional)
- Run app once after install with
--setup
This app stores everything in:
%APPDATA%\MonitorControl\
Files:
app_config.json- contains:
name,ip, andfirst_runflag (first-run config flow)
- contains:
brightness.json- stores last slider brightness value
tv_token.json- Samsung TVWS token file (created after Allow)
app.log- logs
- Left click: open/close brightness slider popup
- Right click: context menu
- Range: 0 → 50
- When you release the slider, the app calculates the delta and sends:
KEY_RIGHTfor increasing brightnessKEY_LEFTfor decreasing brightness
Because it uses key presses, moving the slider from 0 → 50 will send many keys.
Tip:
- Don’t drag like crazy. Slide, release, let it apply.
Things to check:
- Windows hides inactive tray icons sometimes:
- Click the “^” arrow near the tray and see if it’s hidden there.
- Confirm the app is really creating the tray:
- Check
%APPDATA%\MonitorControl\app.log
- Check
If the tray icon shows in dev but not after PyInstaller:
- Make sure
icon.icois included in the build. - Avoid relying on working directory paths.
- Your code uses
resource_path()and_MEIPASSwhich is correct for PyInstaller.
- Ensure monitor + PC are on the same network.
- Ensure the IP is correct.
- Some TVs require being turned on/unlocked.
- Try running:
- installed app with
--setup
- installed app with
This means PyInstaller missed it. Fix by:
- Installing it explicitly and rebuilding: pip install websockets
- Adding it to hiddenimports in the spec (if needed).
Samsung menu layouts can differ by model/firmware. This app navigates with a fixed sequence:
- MENU → RIGHT → DOWN x4 → ENTER → ENTER If your model differs, tweak:
open_brightness_menu()open_brightness_menu_first_time()
- The app talks to your monitor over LAN.
tv_token.jsonis a local token used for authentication after you press Allow.- Do not upload your personal token file to GitHub.
- Do not expose your monitor IP publicly (it’s a LAN IP anyway, but still).
- Multi-monitor support (profiles list)
- Better UI polish (animation / modern styling)
- Direct brightness API if Samsung exposes one (avoid menu navigation)
- Optional hotkeys
Copyright 2026 MRZT721010
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- PyQt6
- samsungtvws




