A high-performance .NET 10 System Monitor for 3.5" Turing Smart Screens on Linux (Turing Smart Screen / Revision A). Features Native AOT for ultra-low memory footprint and a fully customizable JSON theme engine.
- Native AOT: High-performance native binary with ultra-low memory footprint (< 20MB).
- Theme Engine: Fully customizable JSON-based layout system with real transparency support.
- Live Reload: Calibrate your layout in real-time—save the JSON and see changes on the LCD instantly.
- Delta Updates: Intelligent rendering that sends only modified pixels to the hardware for high responsiveness. Overlap-aware redraw ensures dependent elements are refreshed correctly.
- Full Telemetry: Real-time data for CPU, GPU (NVIDIA), RAM, Network, and Weather.
- Auto-Reconnect: Automatic serial port reconnection with exponential backoff and port re-detection. The LCD recovers on its own after USB disconnects/reconnects.
- Robust Error Handling: All failures are logged with appropriate severity (no silent exceptions). The service keeps running even if sensors or the LCD are unavailable.
- Non-Blocking Weather: Weather data is fetched in the background (every 30 min, continuous interval from the last successful fetch) and never stalls the telemetry loop. Includes exponential-backoff retry (5s → 10s → 20s → 40s → 80s, up to 5 retries) so it survives slow network bring-up at boot. The last successful reading is persisted to
/var/lib/turing-monitor/weather.jsonand restored on startup, so the display never shows a stale0°Cafter a reboot. Falls back gracefully if the API is unreachable.
- Nobara Linux / Fedora (Currently developed and tested on Nobara; other distros are not yet tested).
- .NET 10 SDK (required for building).
- Dependencies:
libicu,libssl,libusb. - A 3.5" Turing Smart Screen (Revision A).
We provide a simple installation script that builds the project and sets up a systemd daemon:
chmod +x install.sh
./install.shThe script will:
- Build the binary using Native AOT.
- Install the application to
/usr/local/bin/TuringMonitor. - Configure and start a
systemdservice (turing-monitor.service). - Add your user to the
dialoutgroup for serial port access.
To change the active theme, edit appsettings.json:
{
"Theme": "MyCustomTheme"
}Themes are located in Assets/Themes/.
- Create a new folder in
Assets/Themes/[ThemeName]. - Add a
background.png(480x320). - Create a
theme.jsonfile. - (Optional) Add an
Icons/folder with weather icons (01d.png, etc).
| Field | Description |
|---|---|
Background |
Background image file name. |
FontPath |
Path to a .ttf font file (relative to root). |
DebugMode |
If true, draws red bounding boxes around elements. |
Latitude / Longitude |
Geographical coordinates for weather. |
WeatherApi |
Weather data provider. Default openmeteo (keyless). Optional: openweather or openweathermap (alias) — requires an API key. |
WeatherIconsSource |
Source for weather icons. Default local (uses Icons/{icon}.png from theme). Optional: online — downloads OWM icons to IconCache/ on first use; uses Icons/ only as fallback if the download fails. |
OpenWeatherApiKey |
API key for OpenWeather when WeatherApi=openweather. Recommended to put the key in appsettings.json (OpenWeatherApiKey) instead — it has priority over theme.json. See Weather Providers. |
Text: Renders formatted strings.ProgressBar: Segmented horizontal bar.Gauge: 180° segmented arc.Icon: Dynamic PNG icons based on weather.
CpuName,CpuLoad,CpuTemp,CpuClock,CpuPowerGpuModel,GpuLoad,GpuTemp,GpuPower,VramString,VramPercentRamString,RamPercentNetInMbps,NetOutMbps,NetInString,NetOutStringWeatherTemp,WeatherIconDateTime
TuringMonitor supports two weather data providers, selectable per theme via WeatherApi in theme.json:
| Provider | WeatherApi value |
API Key | Endpoint |
|---|---|---|---|
| Open-Meteo (default) | openmeteo |
none | api.open-meteo.com/v1/forecast |
| OpenWeather (optional) | openweather (or alias openweathermap) |
required | api.openweathermap.org/data/2.5/weather (Current Weather Data 2.5, free tier ~1000 calls/day) |
API Key resolution: when WeatherApi=openweather, the key is resolved as appsettings.json:OpenWeatherApiKey (priority) ?? theme.json:OpenWeatherApiKey. To keep your key out of the theme folder (and out of any shared theme download), place it in appsettings.json or, preferably, appsettings.local.json (gitignored by default — see .gitignore):
{
"OpenWeatherApiKey": "your-api-key-here"
}Fallback behavior:
- If the key is missing or invalid (HTTP 401) with
openweatherconfigured → logsERROR, falls back permanently to Open-Meteo for the current session. - If the OpenWeather call fails transiently (timeout / 5xx / network) → logs
WARNING, keepsopenweatheras the provider, and uses the last cached value. Does not mix providers within a session. - If
WeatherApiis an unknown value → logsERROR, usesopenmeteo. - Open-Meteo (
openmeteo, the default) keeps the existing behavior unchanged.
Refresh scheduling & retry: the cache TTL is 30 minutes continuous from the last successful fetch (not aligned to wall-clock slots like :00/:30 — both APIs return instantaneous conditions, so aligning to fixed slots would only discard valid recently-fetched data). On failure, FetchWithRetryAsync retries up to 5 times with exponential backoff (5s → 10s → 20s → 40s → 80s); if all attempts fail, the next fetch is gated for 80s to avoid hammering the API. The last successful reading (temp, icon, timestamp) is persisted to /var/lib/turing-monitor/weather.json (with a $HOME fallback when not running as a service) and restored on startup if it is less than 6 hours old — so after a reboot the display shows the last known value immediately instead of 0°C while the first fetch is in progress.
Icons: weather icon codes are native OpenWeather codes (01d, 04n, etc.). When WeatherIconsSource=online, icons are downloaded once to Assets/Themes/[Theme]/IconCache/{icon}.png and reused from cache. If a cached icon already exists it is used directly. If the download fails, the icon in Assets/Themes/[Theme]/Icons/{icon}.png is used as fallback; if neither exists, a geometric placeholder is drawn. In local mode (default), only Icons/{icon}.png is used (current behavior).
This project is licensed under the MIT License. Created by bendak.
