{"id":44095133,"url":"https://github.com/nicholaswilde/side-eye","last_synced_at":"2026-02-18T08:01:16.644Z","repository":{"id":336286554,"uuid":"1149060066","full_name":"nicholaswilde/side-eye","owner":"nicholaswilde","description":"👀 A tiny USB monitor that gives your Linux rig the SideEye. 🖥️","archived":false,"fork":false,"pushed_at":"2026-02-11T06:33:54.000Z","size":535,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-11T09:52:51.118Z","etag":null,"topics":["esp32","esp32-c6","rust","rustlang"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicholaswilde.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-03T17:16:21.000Z","updated_at":"2026-02-11T06:33:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nicholaswilde/side-eye","commit_stats":null,"previous_names":["nicholaswilde/side-eye"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/nicholaswilde/side-eye","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholaswilde%2Fside-eye","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholaswilde%2Fside-eye/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholaswilde%2Fside-eye/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholaswilde%2Fside-eye/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicholaswilde","download_url":"https://codeload.github.com/nicholaswilde/side-eye/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicholaswilde%2Fside-eye/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29573400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T07:57:19.261Z","status":"ssl_error","status_checked_at":"2026-02-18T07:57:18.820Z","response_time":162,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["esp32","esp32-c6","rust","rustlang"],"created_at":"2026-02-08T12:06:55.515Z","updated_at":"2026-02-18T08:01:16.638Z","avatar_url":"https://github.com/nicholaswilde.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# :eyes: SideEye: The USB Stat Monitor for Linux :desktop_computer:\n\n[![Coveralls](https://img.shields.io/coveralls/github/nicholaswilde/side-eye/main?style=for-the-badge\u0026logo=coveralls)](https://coveralls.io/github/nicholaswilde/side-eye?branch=main)\n[![task](https://img.shields.io/badge/Task-Enabled-brightgreen?style=for-the-badge\u0026logo=task\u0026logoColor=white)](https://taskfile.dev/#/)\n[![ci](https://img.shields.io/github/actions/workflow/status/nicholaswilde/side-eye/ci.yml?label=CI\u0026style=for-the-badge\u0026logo=github-actions)](https://github.com/nicholaswilde/side-eye/actions/workflows/ci.yml)\n[![docker](https://img.shields.io/github/actions/workflow/status/nicholaswilde/side-eye/docker.yml?label=Docker\u0026style=for-the-badge\u0026logo=docker\u0026tag=latest)](https://github.com/nicholaswilde/side-eye/actions/workflows/docker.yml)\n[![release](https://img.shields.io/github/actions/workflow/status/nicholaswilde/side-eye/release.yml?label=Release\u0026style=for-the-badge\u0026logo=github-actions)](https://github.com/nicholaswilde/side-eye/actions/workflows/release.yml)\n[![Rust](https://img.shields.io/badge/Host-Rust-orange?style=for-the-badge\u0026logo=rust)](https://www.rust-lang.org/)\n[![PlatformIO](https://img.shields.io/badge/Firmware-PlatformIO-blue?style=for-the-badge\u0026logo=platformio)](https://platformio.org/)\n[![Hardware](https://img.shields.io/badge/Hardware-ESP32--C6--GEEK-white?style=for-the-badge\u0026logo=espressif)](https://www.waveshare.com/esp32-c6-geek.htm)\n\n\u003e [!WARNING]\n\u003e This project is currently in active development (v0.X.X) and is **not production-ready**. Features may change, and breaking changes may occur without notice.\n\nSideEye is a tiny USB-powered monitor that gives your Linux rig the \"SideEye\" by displaying real-time system stats on a dedicated LCD. It consists of a lightweight Rust host binary and custom ESP32-C6 firmware.\n\n---\n\n## :gear: System Architecture\n\n1.  **Host (The Sender):** A Rust-based daemon that gathers rich system telemetry (CPU, RAM, Disk, Uptime, Identity) and streams it over USB Serial using structured JSON.\n2.  **Firmware (The Receiver):** Arduino-based firmware running on the [ESP32-C6-GEEK](https://www.waveshare.com/esp32-c6-geek.htm) that parses the JSON payloads and renders a polished, color-coded UI on the built-in 1.14\" LCD.\n\n---\n\n## :stopwatch: Quick Start\n\n### 1. Prerequisites (Linux)\n\nYou will need `pkg-config` and `libudev` development headers for the serial communication library.\n\n```bash\nsudo apt install pkg-config libudev-dev\n```\n\n### 2. Flash the Firmware\n\nConnect your **Waveshare ESP32-C6-GEEK** and flash the receiver code. You can use `task` to build and flash locally:\n\n```bash\ntask firmware:flash\n```\n\nAlternatively, use the provided flash script to automatically download and flash the latest release:\n\n- **Flash:** Execute the `flash.sh` script remotely from GitHub.\n\n```shell\nbash -c \"$(curl -fsSL https://raw.githubusercontent.com/nicholaswilde/side-eye/main/firmware/scripts/flash.sh)\" _ /dev/ttyACM0\n```\n\n\u003e [!WARNING]\n\u003e Running a script directly from the internet with `bash -c \"$(curl...)\"` is a potential security risk. Always review the script's source code before executing it to ensure it is safe. You can view the script [here](https://github.com/nicholaswilde/side-eye/blob/main/firmware/scripts/flash.sh).\n\n\u003e [!NOTE]\n\u003e The script defaults to `/dev/ttyACM0` if no port is specified. It requires `curl`, `unzip`, and [`esptool`](https://docs.espressif.com/projects/esptool/en/latest/esp32/) to be installed.\n\n### 3. Wi-Fi \u0026 MQTT Setup\n\nUpon first boot, the device will enter setup mode:\n1.  Connect to the Wi-Fi AP named **\"SideEye-XXXXXX\"** (where XXXXXX is the last part of your device's MAC) using your phone or laptop.\n2.  Navigate to `192.168.4.1`.\n3.  Enter your Wi-Fi credentials and optional **MQTT Broker** details.\n4.  The device will reboot and show **\"WiFi Online!\"**.\n\n\u003e [!TIP]\n\u003e You can also bake in default credentials at compile-time by creating `firmware/include/secrets.h` (see `secrets.h.example`).\n\n### 4. MQTT Usage\n\nOnce connected to your broker, you can interact with the device via MQTT. For example, to manually rotate the screen:\n\n```bash\nmosquitto_pub -h \u003cMQTT_BROKER_IP\u003e -t \"side-eye/\u003cDEVICE_ID\u003e/set/rotation\" -m \"3\"\n```\n\n#### OTA Update via MQTT\nTrigger a remote firmware update by publishing a direct `.bin` URL:\n\n```bash\nmosquitto_pub -h \u003cMQTT_BROKER_IP\u003e -t \"side-eye/\u003cDEVICE_ID\u003e/set/ota_url\" -m \"https://example.com/firmware.bin\"\n```\n\nOr trigger a manual GitHub update check:\n\n```bash\nmosquitto_pub -h \u003cMQTT_BROKER_IP\u003e -t \"side-eye/\u003cDEVICE_ID\u003e/set/check_update\" -m \"1\"\n```\n\n#### Change UI Theme via MQTT\nSwitch to a custom theme stored on the SD card (e.g., `/themes/cyberpunk`):\n\n```bash\nmosquitto_pub -h \u003cMQTT_BROKER_IP\u003e -t \"side-eye/\u003cDEVICE_ID\u003e/set/theme\" -m \"/themes/cyberpunk\"\n```\n\n### 5. Web OTA Updates\nNavigate to `http://\u003cDEVICE_IP\u003e/update` in your browser to upload a new firmware binary directly. The device will show a visual progress bar on the LCD during the process.\n\n---\n\n## :computer: Host Agent Setup\n\n### 6. Install \u0026 Run the Host Agent\nThe host will automatically attempt to detect the ESP32 on your serial ports.\n\n#### Homebrew (Linux)\n```bash\nbrew tap nicholaswilde/homebrew-tap\nbrew install side-eye-host\nside-eye-host\n```\n\n#### Manual Installation\n\nDownload the binaries from the [latest release](https://github.com/nicholaswilde/side-eye/releases).\n\n#### Run from Source\n```bash\ntask host:run\n```\n\n\u003e [!NOTE]\n\u003e **Expected Behavior:** When the host agent connects to the device, the hardware will automatically restart once. This is a standard feature of the ESP32's auto-reset mechanism triggered by the serial port opening. The firmware is optimized to handle this transition quickly.\n\n---\n\n## :house: Home Assistant Integration\n\nSideEye supports automatic **MQTT Discovery**, making it easy to add to your Home Assistant dashboard.\n\n1.  **Configure MQTT in HA:** Ensure you have the [MQTT integration](https://www.home-assistant.io/integrations/mqtt/) installed and configured in Home Assistant.\n2.  **Device Setup:** During the [Wi-Fi \u0026 MQTT Setup](#3-wi-fi--mqtt-setup), enter your Home Assistant's MQTT broker IP address and credentials.\n3.  **Automatic Discovery:** Once SideEye connects to the broker, it will automatically announce itself.\n4.  **Add to Dashboard:** Navigate to **Settings \u003e Devices \u0026 Services \u003e MQTT** in Home Assistant. You should see a new \"SideEye\" device with sensors for:\n    -   **Hostname, IP, and MAC Address**\n    -   **WiFi RSSI** (Signal Strength)\n    -   **BLE Presence Status** (User proximity)\n    -   **Firmware Version** (with update check support)\n    -   **Device Connectivity Status** (Online/Offline)\n\n---\n\n## :package: Components \u0026 Features\n\n### Rust Host Agent\n- **Presence Notifications:** Triggers native desktop notifications (User Present/Away) based on ESP32 BLE proximity detection.\n- **Multi-Format Configuration:** Supports `side-eye.{toml,yaml,yml,json}` and `.env` files.\n- **Zero-Config Discovery:** Automatically finds the ESP32-C6 by VID (0x303A) and creates a `/dev/side-eye` symlink via udev.\n- **Multi-Device Support:** Seamlessly handles connections to multiple SideEye devices simultaneously.\n- **SD Card Synchronization:** Synchronizes a local host directory to the device's integrated SD card over serial.\n- **Linux Packaging:** Officially supports Homebrew, `.deb` (Debian/Ubuntu), and `.rpm` (Fedora/RHEL) packages, plus systemd integration for auto-start.\n\n### ESP32-C6 Firmware\n- **Custom SD Card Theming:** Load JPEG backgrounds and custom color schemes from the integrated SD card.\n- **Custom Boot Screen:** Display a personalized `boot.jpg` from the SD root during startup.\n- **Catppuccin UI:** Polished, color-coded default interface using the Catppuccin Mocha color palette.\n- **Paged UI:** Cycles through **Identity**, **Resources** (CPU/RAM bars), **Status** (Disk/Uptime), **SD Card**, **Thermal** (CPU Temp/GPU Load), and **Network** pages.\n- **Offline Access:** The **SD Card** page remains accessible via button cycle even when disconnected from the host, showing local storage usage.\n- **Intelligent UI State:** Clean \"Waiting...\" mode when idle, automatically transitioning to a detailed dashboard upon host connection.\n- **Visual Alerts:** Banner changes color based on resource usage thresholds (Mauve -\u003e Yellow -\u003e Flashing Red) and automatically switches to the Resources page.\n- **Network History:** Dedicated page with real-time sparklines for download and upload throughput history.\n- **Global Status Indicators:** A persistent footer row of pixel-art icons (WiFi, MQTT, Host, SD, BLE) provides real-time system status across all dashboard pages.\n- **Home Assistant Integration:** Automatic MQTT Discovery—sensors appear instantly in your HA dashboard.\n- **Power Management:** 1-minute auto-off timeout to save screen life; wakes instantly on button interaction.\n- **Integrated Releases:** Unified GitHub Releases provide synchronized host binaries and a complete firmware bundle (`firmware.bin`, `bootloader.bin`, `partitions.bin`) in a single zip.\n- **OTA Updates (Multi-Channel):**\n  - **Web Update:** Built-in web server at `/update` for browser uploads.\n  - **GitHub Auto-Update:** Periodic 12-hour checks against the GitHub Releases API.\n  - **MQTT Triggered:** Direct URL flash via MQTT command.\n  - **Visual Feedback:** Dedicated LCD update screen with real-time progress bar.\n  - **Persistence:** Automatic post-update \"Success\" notification on boot; LittleFS settings are preserved.\n- **Automated Versioning:** Firmware version is automatically synchronized with the host's `Cargo.toml` during build.\n\n#### SD Card Theme Structure\nThemes are stored in folders under `/themes/`. A theme directory can contain:\n- `theme.json`: Color overrides in hex (e.g., `{\"colors\": {\"base\": \"0x0000\", \"text\": \"0xFFFF\"}}`).\n- `background.jpg`: Default background for all pages.\n- `\u003cpage_name\u003e.jpg`: Page-specific backgrounds (e.g., `identity.jpg`, `resources.jpg`).\n- `/boot.jpg`: (SD root only) Replaces the default booting screen.\n\n\u003e [!TIP]\n\u003e Use the **SD Card Synchronization** feature to automatically manage your themes. Simply place your theme folders inside your local sync directory (configured in `side-eye.toml`), and they will be mirrored to the SideEye's SD card root.\n\n---\n\n## :mouse: Interactivity (Physical Button)\n\nThe onboard \"Boot\" button (GPIO 9) provides full control:\n- **Single Click:** Advance to the next information page (works even when disconnected or wakes the screen if it's off).\n- **Double Click:** Rotate the display 180 degrees (supports any USB port orientation). **Works even on the setup screen!**\n- **Hold (1s):** Toggle the LCD backlight on/off manually.\n- **Long Hold (10s):** Factory Reset. Clears all Wi-Fi and MQTT settings. A countdown will appear on screen.\n\n---\n\n## :wrench: Configuration\n\nSee [host/side-eye.toml.example](host/side-eye.toml.example) for a documented template.\n\nPrecedence (highest to lowest):\n1.  **CLI Flags:** `--port`, `--baud-rate`, `--interval`, `--verbose`, `--config`, `--dry-run`, `--monitor-all`.\n2.  **Environment Variables:** Prefixed with `SIDEEYE_` (e.g., `SIDEEYE_INTERVAL=500`).\n3.  **Config Files:** \n    -   Local: `side-eye.{toml,yaml,yml,json}` in current directory.\n    -   Global: `~/.config/side-eye/config.{toml,yaml,yml,json}`.\n    -   **Thresholds Section:** Configure `cpu_warning`, `cpu_critical`, `ram_warning`, and `ram_critical` (0-100).\n4.  **.env File:** Loaded from the current working directory.\n\n---\n\n## :balance_scale: License\n\nThis project is licensed under the [Apache License 2.0](./LICENSE).\n\n---\n\n## :pencil: Author\n\nThis project was started in 2026 by [Nicholas Wilde](https://github.com/nicholaswilde/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicholaswilde%2Fside-eye","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicholaswilde%2Fside-eye","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicholaswilde%2Fside-eye/lists"}