This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
PcMeter is a Windows system tray application that reads CPU and memory utilization and sends the data over serial to an Arduino-based physical meter device (analog gauges with LEDs). There is also Arduino firmware for the device itself.
There are two Windows tray applications in this repo. The modern one (PcMeter/) supersedes the legacy one (PcMeter (legacy)/).
dotnet build PcMeter/PcMeter.csproj
dotnet run --project PcMeter/PcMeter.csproj
Entry point is App.xaml.cs (App : Application). There is no main window; the app is tray-only with ShutdownMode = OnExplicitShutdown.
App.xaml.cs — central orchestrator. Owns the single-instance Mutex, creates the three services and TrayMenu, and wires up event handlers. Runs a 500ms DispatcherTimer that reads metrics and sends serial data each tick. All menu click handlers are private OnXxxMenuClick() methods here. App.xaml is minimal — no resources or XAML-defined UI.
Navigation/TrayMenu — encapsulates the TaskbarIcon and ContextMenu. Builds the menu items (CPU%, memory%, Connect, Settings, About, Exit) in CreateTrayIcon(), exposes events (ConnectClicked, SettingsClicked, AboutClicked, ExitClicked), and provides UpdateCpuMem(), RefreshMenuState(), and ShowNotification() methods. Implements IDisposable.
Services/
AppSettings— POCO withComPortproperty.Load()/Save()read and write%APPDATA%\PcMeter\settings.jsonviaSystem.Text.Json. Default port isCOM20.MetricsService— CPU% viaPerformanceCounter("Processor", "% Processor Time", "_Total"); Memory% via P/Invoke throughPsApiWrapper. Formula:100 - (available / total * 100). ImplementsIDisposable.SerialService— wrapsSerialPortat 9600 baud.Connect()/Disconnect()/TrySend(cpu, mem). FiresErrorOccurred(message)for unexpected errors andConnectionLostfor silent mid-session drops (unplug, sleep/resume); both events are marshaled to the UI thread via the capturedDispatcher. The timer inApp.xaml.csauto-reconnects each tick when disconnected, and pollsSerialPort.GetPortNames()after each send to catch silent unplugs (USB drivers buffer writes, so no exception is thrown on device removal).PsApiWrapper— static helper; P/Invokespsapi.dll!GetPerformanceInfoand returns(available, total)page counts.
Views/SettingsWindow — lists available COM ports in a ComboBox, pre-selects the saved port, and calls _settings.Save() on OK.
Views/AboutWindow — shows app info, MIT license text, and a clickable URL opened via Process.Start with UseShellExecute = true.
NuGet packages: H.NotifyIcon.Wpf (tray icon), System.IO.Ports (serial), System.Diagnostics.PerformanceCounter (CPU stats).
The Windows app sends to the Arduino:
C{0-100}\r— CPU percentageM{0-100}\r— memory percentage
Messages are sent together every 500ms: C{cpu}\rM{mem}\r
Arduino firmware (arduino/pcmeter.ino) — runs on an Arduino Leonardo at 9600 baud. Smooths values using a rolling average of 20 readings, drives two analog meters via PWM, and controls green/red LEDs (red zone ≥80%). Includes a screensaver mode when no serial data is received for 2 seconds.