plc-checkweigher 1.32.3 → 1.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/plc_checkweigher +121 -13
- package/package.json +1 -1
- package/setup.sh +30 -2
package/bin/plc_checkweigher
CHANGED
|
@@ -174,12 +174,13 @@ restart)
|
|
|
174
174
|
need_sudo
|
|
175
175
|
banner "Restarting services"
|
|
176
176
|
echo ""
|
|
177
|
-
spin_start "Restarting plc_watcher and
|
|
178
|
-
sudo systemctl restart plc_watcher plc_web
|
|
177
|
+
spin_start "Restarting plc_watcher, plc_web and plc_selfheal"
|
|
178
|
+
sudo systemctl restart plc_watcher plc_web plc_selfheal 2>/dev/null \
|
|
179
|
+
|| sudo systemctl restart plc_watcher plc_web
|
|
179
180
|
sleep 2
|
|
180
181
|
spin_ok
|
|
181
182
|
echo ""
|
|
182
|
-
systemctl status plc_watcher plc_web --no-pager | grep -E 'Active|Main PID'
|
|
183
|
+
systemctl status plc_watcher plc_web plc_selfheal --no-pager 2>/dev/null | grep -E 'Active|Main PID'
|
|
183
184
|
echo ""
|
|
184
185
|
;;
|
|
185
186
|
|
|
@@ -187,8 +188,9 @@ start)
|
|
|
187
188
|
need_sudo
|
|
188
189
|
banner "Starting services"
|
|
189
190
|
echo ""
|
|
190
|
-
spin_start "Starting plc_watcher and
|
|
191
|
-
sudo systemctl start plc_watcher plc_web
|
|
191
|
+
spin_start "Starting plc_watcher, plc_web and plc_selfheal"
|
|
192
|
+
sudo systemctl start plc_watcher plc_web plc_selfheal 2>/dev/null \
|
|
193
|
+
|| sudo systemctl start plc_watcher plc_web
|
|
192
194
|
sleep 1
|
|
193
195
|
spin_ok
|
|
194
196
|
echo ""
|
|
@@ -198,12 +200,15 @@ stop)
|
|
|
198
200
|
need_sudo
|
|
199
201
|
banner "Stopping services"
|
|
200
202
|
echo ""
|
|
201
|
-
|
|
203
|
+
# Stop the self-healing daemon FIRST — otherwise it would detect the
|
|
204
|
+
# watcher/web going down and immediately restart them, fighting this stop.
|
|
205
|
+
spin_start "Stopping plc_selfheal, plc_watcher and plc_web"
|
|
206
|
+
sudo systemctl stop plc_selfheal 2>/dev/null || true
|
|
202
207
|
sudo systemctl stop plc_watcher plc_web
|
|
203
208
|
spin_ok
|
|
204
209
|
echo ""
|
|
205
210
|
warn "Services stopped — will restart automatically on next boot"
|
|
206
|
-
warn "To disable auto-start: sudo systemctl disable plc_watcher plc_web"
|
|
211
|
+
warn "To disable auto-start: sudo systemctl disable plc_watcher plc_web plc_selfheal"
|
|
207
212
|
echo ""
|
|
208
213
|
;;
|
|
209
214
|
|
|
@@ -235,6 +240,87 @@ queue)
|
|
|
235
240
|
echo ""
|
|
236
241
|
;;
|
|
237
242
|
|
|
243
|
+
# ── Self-healing daemon ────────────────────────────────────────────────────────
|
|
244
|
+
selfheal)
|
|
245
|
+
SUBCMD="${1:-status}"
|
|
246
|
+
shift || true
|
|
247
|
+
case "$SUBCMD" in
|
|
248
|
+
status)
|
|
249
|
+
banner "Self-Healing Daemon"
|
|
250
|
+
echo ""
|
|
251
|
+
ACTIVE=$(systemctl is-active plc_selfheal 2>/dev/null || true)
|
|
252
|
+
ENABLED=$(systemctl is-enabled plc_selfheal 2>/dev/null || true)
|
|
253
|
+
if [[ "$ACTIVE" == "active" ]]; then
|
|
254
|
+
ok "plc_selfheal: RUNNING (auto-start: ${ENABLED})"
|
|
255
|
+
else
|
|
256
|
+
warn "plc_selfheal: ${ACTIVE} (auto-start: ${ENABLED})"
|
|
257
|
+
info "Start it: sudo systemctl start plc_selfheal"
|
|
258
|
+
fi
|
|
259
|
+
echo ""
|
|
260
|
+
# Last-cycle / throttle state
|
|
261
|
+
_ST="/home/pi/reports/health/.selfheal_state.json"
|
|
262
|
+
if [[ -f "$_ST" ]]; then
|
|
263
|
+
"${PYTHON}" - "$_ST" << 'PYEOF' 2>/dev/null || true
|
|
264
|
+
import json, sys, time
|
|
265
|
+
try:
|
|
266
|
+
d = json.load(open(sys.argv[1]))
|
|
267
|
+
except Exception:
|
|
268
|
+
sys.exit(0)
|
|
269
|
+
lc = d.get("last_cycle", 0)
|
|
270
|
+
if lc:
|
|
271
|
+
age = int(time.time() - lc)
|
|
272
|
+
print(f" Last self-heal sweep: {age}s ago")
|
|
273
|
+
rep = d.get("reported", {})
|
|
274
|
+
if rep:
|
|
275
|
+
print(f" Active unresolved problems: {len(rep)}")
|
|
276
|
+
for k in rep: print(f" • {k}")
|
|
277
|
+
else:
|
|
278
|
+
print(" No unresolved problems")
|
|
279
|
+
PYEOF
|
|
280
|
+
else
|
|
281
|
+
info "No sweep has run yet (daemon may have just started)"
|
|
282
|
+
fi
|
|
283
|
+
echo ""
|
|
284
|
+
# Pending health reports on disk
|
|
285
|
+
_HD="/home/pi/reports/health"
|
|
286
|
+
if [[ -d "$_HD" ]]; then
|
|
287
|
+
_N=$(find "$_HD" -maxdepth 1 -name 'health_*.txt' 2>/dev/null | wc -l)
|
|
288
|
+
[[ "${_N:-0}" -gt 0 ]] && info "${_N} health report(s) in ${_HD}"
|
|
289
|
+
fi
|
|
290
|
+
echo ""
|
|
291
|
+
info "Recent activity: plc_checkweigher selfheal logs"
|
|
292
|
+
echo ""
|
|
293
|
+
;;
|
|
294
|
+
logs)
|
|
295
|
+
banner "Self-Heal Logs"
|
|
296
|
+
echo ""
|
|
297
|
+
exec journalctl -u plc_selfheal -n 50 -f --no-pager
|
|
298
|
+
;;
|
|
299
|
+
now|run)
|
|
300
|
+
banner "Self-Heal — Immediate Sweep"
|
|
301
|
+
need_sudo
|
|
302
|
+
echo ""
|
|
303
|
+
spin_start "Running one self-heal cycle"
|
|
304
|
+
sudo "${PYTHON}" -c "
|
|
305
|
+
import sys; sys.path.insert(0, '${INSTALL_DIR}')
|
|
306
|
+
import selfheal
|
|
307
|
+
healed, failed, env = selfheal.run_cycle()
|
|
308
|
+
selfheal.maybe_report(healed, failed, env)
|
|
309
|
+
print('HEALED:', len(healed), '| UNRESOLVED:', len(failed))
|
|
310
|
+
for k,d in healed: print(' [HEALED]', k, '-', d)
|
|
311
|
+
for k,d in failed: print(' [FAIL] ', k, '-', d)
|
|
312
|
+
" && spin_ok || spin_warn "Cycle completed with issues"
|
|
313
|
+
echo ""
|
|
314
|
+
;;
|
|
315
|
+
*)
|
|
316
|
+
echo "Usage: plc_checkweigher selfheal [status|logs|now]"
|
|
317
|
+
echo " status — daemon state, last sweep, unresolved problems (default)"
|
|
318
|
+
echo " logs — follow the self-heal journal"
|
|
319
|
+
echo " now — run one self-heal sweep immediately"
|
|
320
|
+
;;
|
|
321
|
+
esac
|
|
322
|
+
;;
|
|
323
|
+
|
|
238
324
|
# ── Push test ─────────────────────────────────────────────────────────────────
|
|
239
325
|
push-test)
|
|
240
326
|
banner "SMB Push Test"
|
|
@@ -1296,7 +1382,8 @@ update)
|
|
|
1296
1382
|
# ── Update systemd unit files if they changed ─────────────────────────────
|
|
1297
1383
|
_UNITS_UPDATED=0
|
|
1298
1384
|
for _svc_src in "${INSTALL_DIR}/plc_watcher.service" \
|
|
1299
|
-
"${INSTALL_DIR}/web/plc_web.service"
|
|
1385
|
+
"${INSTALL_DIR}/web/plc_web.service" \
|
|
1386
|
+
"${INSTALL_DIR}/plc_selfheal.service"; do
|
|
1300
1387
|
[[ ! -f "$_svc_src" ]] && continue
|
|
1301
1388
|
_svc_dst="/etc/systemd/system/$(basename "$_svc_src")"
|
|
1302
1389
|
if [[ ! -f "$_svc_dst" ]] || ! diff -q "$_svc_src" "$_svc_dst" &>/dev/null; then
|
|
@@ -1309,6 +1396,22 @@ update)
|
|
|
1309
1396
|
spin_ok "systemd reloaded"
|
|
1310
1397
|
fi
|
|
1311
1398
|
|
|
1399
|
+
# ── Self-healing daemon present + enabled (retrofit older installs) ────────
|
|
1400
|
+
spin_start "Self-healing daemon"
|
|
1401
|
+
if [[ -f "${INSTALL_DIR}/selfheal.py" && -f /etc/systemd/system/plc_selfheal.service ]]; then
|
|
1402
|
+
if ! systemctl is-enabled --quiet plc_selfheal 2>/dev/null; then
|
|
1403
|
+
sudo systemctl enable plc_selfheal 2>/dev/null || true
|
|
1404
|
+
spin_ok "plc_selfheal enabled"
|
|
1405
|
+
elif ! systemctl is-active --quiet plc_selfheal 2>/dev/null; then
|
|
1406
|
+
sudo systemctl start plc_selfheal 2>/dev/null || true
|
|
1407
|
+
spin_ok "plc_selfheal started"
|
|
1408
|
+
else
|
|
1409
|
+
spin_ok "plc_selfheal active"
|
|
1410
|
+
fi
|
|
1411
|
+
else
|
|
1412
|
+
spin_warn "selfheal.py or unit missing — will be installed on next full setup"
|
|
1413
|
+
fi
|
|
1414
|
+
|
|
1312
1415
|
# ── Update Plymouth boot splash ───────────────────────────────────────────
|
|
1313
1416
|
_THEME_DIR="/usr/share/plymouth/themes/saismruth"
|
|
1314
1417
|
_LOGO_SRC="${INSTALL_DIR}/assets/logo.png"
|
|
@@ -1566,6 +1669,7 @@ SUDOEOF
|
|
|
1566
1669
|
if [[ $_CODE_CHANGED -eq 1 || $_UNITS_UPDATED -eq 1 ]]; then
|
|
1567
1670
|
spin_start "Restarting services"
|
|
1568
1671
|
sudo systemctl restart plc_watcher plc_web 2>/dev/null
|
|
1672
|
+
sudo systemctl restart plc_selfheal 2>/dev/null || true
|
|
1569
1673
|
sleep 2
|
|
1570
1674
|
spin_ok "Services restarted"
|
|
1571
1675
|
else
|
|
@@ -1699,12 +1803,13 @@ uninstall)
|
|
|
1699
1803
|
# ── 1. Stop and disable services ─────────────────────────────────────────
|
|
1700
1804
|
echo ""
|
|
1701
1805
|
ustep "Stopping and disabling services"
|
|
1702
|
-
for SVC in plc_watcher plc_web; do
|
|
1806
|
+
for SVC in plc_selfheal plc_watcher plc_web; do
|
|
1703
1807
|
systemctl is-active --quiet "$SVC" 2>/dev/null && sudo systemctl stop "$SVC" 2>/dev/null || true
|
|
1704
1808
|
systemctl is-enabled --quiet "$SVC" 2>/dev/null && sudo systemctl disable "$SVC" 2>/dev/null || true
|
|
1705
1809
|
done
|
|
1706
1810
|
sudo rm -f /etc/systemd/system/plc_watcher.service \
|
|
1707
|
-
/etc/systemd/system/plc_web.service
|
|
1811
|
+
/etc/systemd/system/plc_web.service \
|
|
1812
|
+
/etc/systemd/system/plc_selfheal.service
|
|
1708
1813
|
spin_ok "Services removed"
|
|
1709
1814
|
|
|
1710
1815
|
# ── 2. System drop-ins ───────────────────────────────────────────────────
|
|
@@ -1858,11 +1963,14 @@ help|--help|-h)
|
|
|
1858
1963
|
echo " fix -errors Scan journal, verify RT/permissions/PLC/config"
|
|
1859
1964
|
echo " logs Stream live logs (plc_watcher + plc_web)"
|
|
1860
1965
|
echo " queue Show SMB pending queue and delivery ledger"
|
|
1966
|
+
echo " selfheal status Self-healing daemon state + unresolved problems"
|
|
1967
|
+
echo " selfheal logs Follow the self-heal journal"
|
|
1968
|
+
echo " selfheal now Run one self-heal sweep immediately"
|
|
1861
1969
|
echo ""
|
|
1862
1970
|
echo -e " ${W}Services${NC}"
|
|
1863
|
-
echo " start Start
|
|
1864
|
-
echo " stop Stop
|
|
1865
|
-
echo " restart Restart
|
|
1971
|
+
echo " start Start watcher, web and self-heal"
|
|
1972
|
+
echo " stop Stop all services"
|
|
1973
|
+
echo " restart Restart all services"
|
|
1866
1974
|
echo ""
|
|
1867
1975
|
echo -e " ${W}Network${NC}"
|
|
1868
1976
|
echo " wifi Scan and switch WiFi network"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plc-checkweigher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"description": "One-command installer for the PLC Check-Weigher system on Raspberry Pi (PREEMPT_RT kernel, Python stack, WiFi, SMB, systemd RT services)",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"postinstall": "node bin/cli.js"
|
package/setup.sh
CHANGED
|
@@ -432,9 +432,37 @@ WantedBy=multi-user.target
|
|
|
432
432
|
EOF
|
|
433
433
|
ok "plc_web.service (Nice=-10)"
|
|
434
434
|
|
|
435
|
+
# ── Self-healing daemon — auto-repairs services/files/configs at runtime ──
|
|
436
|
+
cat > /etc/systemd/system/plc_selfheal.service << EOF
|
|
437
|
+
[Unit]
|
|
438
|
+
Description=PLC Check-Weigher Self-Healing Daemon
|
|
439
|
+
After=network.target plc_watcher.service plc_web.service
|
|
440
|
+
Wants=plc_watcher.service plc_web.service
|
|
441
|
+
|
|
442
|
+
[Service]
|
|
443
|
+
Type=simple
|
|
444
|
+
User=root
|
|
445
|
+
WorkingDirectory=${INSTALL_DIR}
|
|
446
|
+
Environment=PYTHONUNBUFFERED=1
|
|
447
|
+
ExecStart=${VENV_DIR}/bin/python3 -u ${INSTALL_DIR}/selfheal.py
|
|
448
|
+
Restart=always
|
|
449
|
+
RestartSec=10
|
|
450
|
+
Nice=10
|
|
451
|
+
CPUAffinity=0 1 2
|
|
452
|
+
IOSchedulingClass=idle
|
|
453
|
+
StandardOutput=journal
|
|
454
|
+
StandardError=journal
|
|
455
|
+
|
|
456
|
+
[Install]
|
|
457
|
+
WantedBy=multi-user.target
|
|
458
|
+
EOF
|
|
459
|
+
cp /etc/systemd/system/plc_selfheal.service "${INSTALL_DIR}/plc_selfheal.service"
|
|
460
|
+
chown "${PI_USER}:${PI_USER}" "${INSTALL_DIR}/plc_selfheal.service"
|
|
461
|
+
ok "plc_selfheal.service (auto-repair · cores 0-2 · Nice=10)"
|
|
462
|
+
|
|
435
463
|
systemctl daemon-reload
|
|
436
|
-
systemctl enable plc_watcher.service plc_web.service
|
|
437
|
-
ok "
|
|
464
|
+
systemctl enable plc_watcher.service plc_web.service plc_selfheal.service
|
|
465
|
+
ok "All services enabled — start automatically after reboot"
|
|
438
466
|
|
|
439
467
|
cp /etc/systemd/system/plc_watcher.service "${INSTALL_DIR}/plc_watcher.service"
|
|
440
468
|
chown "${PI_USER}:${PI_USER}" "${INSTALL_DIR}/plc_watcher.service"
|