Плата принимает по 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>
172 lines
9.4 KiB
Markdown
172 lines
9.4 KiB
Markdown
# 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`:
|
||
|
||
1. загружает `LibreHardwareMonitorLib.dll` из `D:\Soft\LibreHardwareMonitor`;
|
||
2. включает мониторинг CPU, ищет сенсоры `Temperature/CPU Package` и
|
||
`Load/CPU Total`;
|
||
3. находит COM-порт по `VID_303A&PID_1001` (не по фиксированному номеру: номер
|
||
меняется при перетыкании в другой разъём);
|
||
4. раз в секунду пишет строку протокола;
|
||
5. при исчезновении порта (перезагрузка платы, перезаливка прошивки) —
|
||
переподключается в цикле, не падая.
|
||
|
||
**Требует прав администратора**: без них драйвер LHM не загружается и
|
||
температура приходит пустой.
|
||
|
||
**Автозапуск** — задание в Планировщике заданий: триггер «при входе в систему»,
|
||
галка «Выполнить с наивысшими правами», окно скрыто.
|
||
|
||
## Установка LibreHardwareMonitor
|
||
|
||
Каталог `D:\Soft\LibreHardwareMonitor` — вне репозитория Arduino. Само
|
||
приложение не запускается, нужны только `LibreHardwareMonitorLib.dll` и её
|
||
драйвер.
|
||
|
||
## Порядок работ и риски
|
||
|
||
1. **Определить пины I2C дисплея эмпирически.** Шелкография подписывает
|
||
`GPIO8/GPIO9` (дефолтные Wire-пины ESP32-C3), но встроенный OLED у плат этого
|
||
семейства обычно на `GPIO5/GPIO6`. Первый шаг — залить I2C-сканер и найти
|
||
адрес экрана перебором обеих пар. Пины не угадывать.
|
||
2. Прошивка: вывод фиксированной заглушки на экран — убедиться в геометрии и
|
||
смещении 72×40.
|
||
3. Приём и разбор строк, `NO DATA` по тайм-ауту.
|
||
4. График.
|
||
5. Агент, затем автозапуск.
|
||
|
||
Прочие риски:
|
||
|
||
- **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, а не к разводке
|
||
встроенного экрана.
|