Runbook восстановления OPi на новой SD-карте + systemd-юнит
Инцидент 22.07: ФС ушла в read-only — захват кадра и SSH отвалились, heartbeat и MQTT-вес продолжали работать. В репозитории не хватало юнита и инструкции подъёма с нуля. - orange_pi/scales.service (восстановлен по systemctl status) - RECOVERY.md: установка, проверки, продление жизни карты, диагностика через MQTT без SSH
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
||||
# Восстановление Orange Pi на новой SD-карте
|
||||
|
||||
Runbook на случай, когда карта деградировала и устройство надо поднять с нуля.
|
||||
Составлен во время инцидента 22.07.2026: ФС ушла в read-only — захват кадра и SSH
|
||||
отвалились, при этом heartbeat и публикация веса в MQTT продолжали работать.
|
||||
|
||||
## Что взять на пост
|
||||
|
||||
- новая SD-карта, **high-endurance** (Samsung PRO Endurance / SanDisk Max Endurance);
|
||||
32 ГБ хватает с запасом — занято ~12%
|
||||
- образ Armbian для Orange Pi PC, записанный заранее
|
||||
- `orange_pi/scales.py`, `orange_pi/outbox.py`, `orange_pi/scales.service` из этого репозитория
|
||||
- старую карту НЕ выбрасывать: с неё может понадобиться вытащить остатки очереди outbox
|
||||
|
||||
## 1. Система
|
||||
|
||||
apt update
|
||||
apt install -y python3 python3-pip ffmpeg
|
||||
pip3 install paho-mqtt # на свежих Debian/Armbian добавить --break-system-packages
|
||||
|
||||
Больше внешних зависимостей нет — всё остальное в скрипте из stdlib.
|
||||
|
||||
## 2. Файлы
|
||||
|
||||
Рабочий файл на устройстве — именно `/root/scales.py`; репозиторий на OPi не клонируется,
|
||||
файл доставляется вручную. `outbox.py` кладётся рядом, в `/root`.
|
||||
|
||||
cp scales.py outbox.py /root/
|
||||
|
||||
Актуальную версию можно скачать прямо с сервера:
|
||||
|
||||
curl -s -o /root/scales.py https://scales.zeroday.su/testphotos/scales.py
|
||||
|
||||
## 3. Сервис
|
||||
|
||||
cp scales.service /etc/systemd/system/scales.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now scales.service
|
||||
systemctl status scales.service --no-pager
|
||||
|
||||
## 4. Проверки после старта
|
||||
|
||||
# в логе должны появиться MQTT1/MQTT2, GPIO, OUTBOX, HEARTBEAT
|
||||
journalctl -u scales.service -n 30 --no-pager
|
||||
|
||||
# весовой терминал
|
||||
ls -l /dev/ttyUSB0
|
||||
|
||||
# камера — тот же вызов, что внутри grab_frame()
|
||||
ffmpeg -y -loglevel error -rtsp_transport tcp -i "<RTSP_URL из scales.py>" \
|
||||
-frames:v 1 -update 1 -q:v 2 -f image2 /tmp/scale_frame.jpg && ls -l /tmp/scale_frame.jpg
|
||||
|
||||
# офлайн-распознавание на боксе
|
||||
curl -s http://192.168.20.4:5010/health
|
||||
|
||||
# сервер принимает (ожидаемый ответ: {"error":"event_id required"})
|
||||
curl -s -X POST -H "Content-Type: application/json" -d '{}' https://scales.zeroday.su/api/local-plate
|
||||
|
||||
Финальная проверка — кнопка «Тест-снимок» в панели: фото должно появиться в заездах.
|
||||
|
||||
## 5. Чтобы карта прожила дольше
|
||||
|
||||
Главный убийца SD-карт — постоянная запись логов.
|
||||
|
||||
mkdir -p /etc/systemd/journald.conf.d
|
||||
printf '[Journal]\nStorage=volatile\nRuntimeMaxUse=32M\n' > /etc/systemd/journald.conf.d/volatile.conf
|
||||
systemctl restart systemd-journald
|
||||
|
||||
Убедиться, что `/tmp` — tmpfs (туда пишется кадр перед отправкой):
|
||||
|
||||
findmnt /tmp
|
||||
|
||||
Если нет — добавить в `/etc/fstab`:
|
||||
|
||||
tmpfs /tmp tmpfs defaults,nosuid,nodev,size=128M 0 0
|
||||
|
||||
На перспективу: перенос системы на USB-SSD или eMMC снимает проблему целиком.
|
||||
|
||||
## Диагностика без SSH
|
||||
|
||||
Устройство управляется через MQTT-брокер даже когда SSH недоступен
|
||||
(на сервере: `localhost:1883`, пользователь `scales-server`).
|
||||
|
||||
# живой heartbeat раз в 30 с — значит процесс жив
|
||||
mosquitto_sub -h 127.0.0.1 -p 1883 -u scales-server -P '<пароль>' -t 'scale/device/status' -v
|
||||
|
||||
# команды: ping (мгновенный статус), test-shot (проверка камеры), reboot
|
||||
mosquitto_pub -h 127.0.0.1 -p 1883 -u scales-server -P '<пароль>' -t 'scale/device/cmd' -m '{"cmd":"ping"}'
|
||||
|
||||
Как читать симптомы:
|
||||
|
||||
| признак | что значит |
|
||||
|---|---|
|
||||
| heartbeat идёт, на `ping` отвечает мгновенно | процесс жив, ресурсы в порядке |
|
||||
| `outbox_pending: 0`, но заездов на сервере нет | `capture_and_send` вышел до постановки в очередь — не получен кадр |
|
||||
| `test-shot` не даёт фото, а RTSP из VLC играет | причина локальная на OPi: запись в `/tmp` или ffmpeg |
|
||||
| SSH рвёт соединение на key exchange | sshd не может создать сессию — характерно для read-only ФС |
|
||||
|
||||
Совпадение последних трёх — почти наверняка карта.
|
||||
|
||||
## Известная недоработка
|
||||
|
||||
`capture_and_send()` при неудачном захвате кадра выходит по `return` **до** постановки
|
||||
события в очередь. Значит отказ камеры теряет не фото, а всю запись о взвешивании —
|
||||
именно так были потеряны заезды 20.07.2026. Вес должен доезжать до сервера и без фото;
|
||||
поправить при ближайшем доступе к устройству.
|
||||
Reference in New Issue
Block a user