Плата принимает по USB-CDC строки "T=67.0;L=34" от агента на ПК и рисует крупную цифру, загрузку и график за последнюю минуту на экране 72x40. Пины дисплея (SDA=5, SCL=6) определены сканером, а не по шелкографии: подписи GPIO8/GPIO9 на плате - это дефолтные Wire-пины чипа. Агент читает сенсоры через LibreHardwareMonitorLib. С версии 0.9.5 она требует отдельно установленный драйвер PawnIO: без него загрузка CPU читается, а температуры пусты даже под администратором. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9.4 KiB
CPU Temp — настольный индикатор температуры процессора
Дата: 2026-09-14 Статус: дизайн согласован, реализация не начата
Задача
Показывать температуру CPU домашнего ПК на отдельной плате ESP32-C3 с OLED-экраном 72×40, стоящей на столе. Кроме текущего значения — история за последнюю минуту, чтобы было видно, греется машина под нагрузкой или нет.
Оборудование
| Параметр | Значение |
|---|---|
| Плата | ESP32-C3 (QFN32), ревизия v0.4, встроенный OLED 0.42″ |
| Флеш | 4 МБ (XMC), кристалл 40 МГц |
| Подключение | нативный USB Espressif, VID_303A&PID_1001, на текущем ПК — COM4 |
| FQBN | esp32:esp32:esp32c3 (ядро esp32 3.3.8) |
| ПК | Windows 10 Pro, Intel Core i5-11400H |
Архитектура
LibreHardwareMonitorLib.dll ──> PowerShell-агент ──COM4 (USB CDC)──> ESP32-C3 ──I2C──> OLED 72×40
(драйвер, MSR) раз в секунду текстовая строка U8g2
Плата ничего не измеряет сама и не хранит настроек: принимает строки и рисует. Вся работа с железом ПК — на стороне агента.
Почему так
- Данные с ПК, а не встроенный датчик ESP32. Встроенный сенсор меряет собственный кристалл платы — величина малоинформативная.
- Температуру CPU читает LibreHardwareMonitor, а не наш код. Прямое чтение
требует MSR-регистров через подписанный драйвер ядра и отдельных формул под
каждое поколение CPU. LHM даёт готовую
LibreHardwareMonitorLib.dll. - Транспорт — COM-порт, не Wi-Fi. Плата и так питается по USB от этого же ПК: провод уже есть. Нет настройки сети, паролей, IP и mDNS.
- Агент на PowerShell, не на C#. Загрузка .NET-сборки доступна из PowerShell напрямую; компилятор и IDE не нужны.
Протокол
Одна строка в секунду, \n в конце:
T=67.0;L=34
| Ключ | Смысл | Формат |
|---|---|---|
T |
CPU Package, °C | дробное |
L |
общая загрузка CPU, % | целое |
Формат «ключ=значение» выбран ради расширяемости: добавление G= (GPU) или
M= (RAM) не ломает старую прошивку — неизвестные ключи прошивка молча
игнорирует. Скорость 115200.
Отсутствие данных. Если валидная строка не приходила дольше 5 секунд,
прошивка показывает NO DATA и перестаёт дописывать историю (чтобы пауза не
рисовалась как провал температуры).
Экран
Разрешение 72×40, монохром, драйвер SSD1306 с ненулевым смещением по обеим осям.
Используется U8G2_SSD1306_72X40_ER_F_HW_I2C из U8g2 2.36.19 (уже установлена).
┌────────────────────────┐
│ 67° 34% │ крупные цифры (~24 px) + мелкая загрузка
│ │
│ ▁▂▃▃▄▆█▆▅▄▃▂▂▁▁▂▃▄▅▆ │ спарклайн: 72 точки = 72 секунды
└────────────────────────┘
Шкала графика фиксированная: 30–90 °C. Автомасштаб отвергнут: в простое шум ±1 °C рисовался бы горами и создавал ложную тревогу. Значения вне диапазона обрезаются по краю.
История — кольцевой буфер на 72 значения (по пикселю на точку, одно значение в секунду).
Состав проекта
CPU_temp/
CPU_temp.ino setup/loop, тайм-аут «нет данных»
link.h / link.cpp чтение строки из Serial, разбор в структуру CpuStats
ui.h / ui.cpp отрисовка U8g2, кольцевой буфер истории
docs/ этот документ
agent/
cpu_temp_agent.ps1 агент для ПК
README.md установка и автозапуск
Границы модулей: link ничего не знает об экране и отдаёт только структуру с
данными и признаком свежести; ui не знает, откуда данные взялись, и принимает
ту же структуру. Оба тестируются и меняются независимо.
Агент
Файл agent/cpu_temp_agent.ps1:
- загружает
LibreHardwareMonitorLib.dllизD:\Soft\LibreHardwareMonitor; - включает мониторинг CPU, ищет сенсоры
Temperature/CPU PackageиLoad/CPU Total; - находит COM-порт по
VID_303A&PID_1001(не по фиксированному номеру: номер меняется при перетыкании в другой разъём); - раз в секунду пишет строку протокола;
- при исчезновении порта (перезагрузка платы, перезаливка прошивки) — переподключается в цикле, не падая.
Требует прав администратора: без них драйвер LHM не загружается и температура приходит пустой.
Автозапуск — задание в Планировщике заданий: триггер «при входе в систему», галка «Выполнить с наивысшими правами», окно скрыто.
Установка LibreHardwareMonitor
Каталог D:\Soft\LibreHardwareMonitor — вне репозитория Arduino. Само
приложение не запускается, нужны только LibreHardwareMonitorLib.dll и её
драйвер.
Порядок работ и риски
- Определить пины I2C дисплея эмпирически. Шелкография подписывает
GPIO8/GPIO9(дефолтные Wire-пины ESP32-C3), но встроенный OLED у плат этого семейства обычно наGPIO5/GPIO6. Первый шаг — залить I2C-сканер и найти адрес экрана перебором обеих пар. Пины не угадывать. - Прошивка: вывод фиксированной заглушки на экран — убедиться в геометрии и смещении 72×40.
- Приём и разбор строк,
NO DATAпо тайм-ауту. - График.
- Агент, затем автозапуск.
Прочие риски:
- COM4 — тот же порт, через который прошивается плата. Перед каждой
заливкой агента надо останавливать, иначе
PermissionError. То же ограничение уже описано вCLAUDE.mdдля монитора порта Arduino IDE. USB CDC On Bootдолжен быть включён в настройках платы, иначеSerialуйдёт в аппаратный UART, а не в USB.
Решения, принятые явно
- Git: проект пока не добавляется в белый список
.gitignore. Заливаем, когда появятся первые рабочие результаты, чтобы не засорять публичную историю. - Автозапуск агента: через Планировщик заданий (вариант B), а не ручной ярлык.
- Каталог LHM:
D:\Soft\LibreHardwareMonitor.
Вне рамок (YAGNI)
- GPU, RAM, частоты, вентиляторы — протокол расширяем, но сейчас не делаем.
- Переключение экранов кнопкой BOOT.
- Wi-Fi, веб-панель, сохранение настроек в LittleFS — прошивке нечего хранить.
Подтверждённые пины (Задача 1, 2026-09-14)
Сканер tools/i2c_scan перебрал пары (5,6), (6,5), (8,9), (9,8). Устройство
отвечает только на одной:
SDA=5 SCL=6: device 0x3C
Итого: SDA = GPIO5, SCL = GPIO6, адрес 0x3C. Подпись GPIO8/GPIO9 на
шелкографии относится к дефолтным Wire-пинам ESP32-C3, а не к разводке
встроенного экрана.