plc-checkweigher 1.20.0 → 1.22.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 +346 -6
- package/package.json +1 -1
package/bin/plc_checkweigher
CHANGED
|
@@ -588,19 +588,20 @@ smb-config)
|
|
|
588
588
|
|
|
589
589
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
590
590
|
# FIX — auto-detect and repair common issues
|
|
591
|
-
# Usage: fix [-wifi] [-health] [-programs] (no flags = run all)
|
|
591
|
+
# Usage: fix [-wifi] [-health] [-programs] [-errors] (no flags = run all)
|
|
592
592
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
593
593
|
fix)
|
|
594
|
-
FIX_WIFI=0; FIX_HEALTH=0; FIX_PROGRAMS=0
|
|
594
|
+
FIX_WIFI=0; FIX_HEALTH=0; FIX_PROGRAMS=0; FIX_ERRORS=0
|
|
595
595
|
if [[ $# -eq 0 ]]; then
|
|
596
|
-
FIX_WIFI=1; FIX_HEALTH=1; FIX_PROGRAMS=1
|
|
596
|
+
FIX_WIFI=1; FIX_HEALTH=1; FIX_PROGRAMS=1; FIX_ERRORS=1
|
|
597
597
|
else
|
|
598
598
|
for _flag in "$@"; do
|
|
599
599
|
case "$_flag" in
|
|
600
600
|
-wifi) FIX_WIFI=1 ;;
|
|
601
601
|
-health) FIX_HEALTH=1 ;;
|
|
602
602
|
-programs) FIX_PROGRAMS=1 ;;
|
|
603
|
-
|
|
603
|
+
-errors) FIX_ERRORS=1 ;;
|
|
604
|
+
*) warn "Unknown flag: $_flag (valid: -wifi -health -programs -errors)" ;;
|
|
604
605
|
esac
|
|
605
606
|
done
|
|
606
607
|
fi
|
|
@@ -612,7 +613,8 @@ fix)
|
|
|
612
613
|
[[ $FIX_WIFI -eq 1 ]] && _LOG_MODES="${_LOG_MODES:+${_LOG_MODES}-}wifi"
|
|
613
614
|
[[ $FIX_HEALTH -eq 1 ]] && _LOG_MODES="${_LOG_MODES:+${_LOG_MODES}-}health"
|
|
614
615
|
[[ $FIX_PROGRAMS -eq 1 ]] && _LOG_MODES="${_LOG_MODES:+${_LOG_MODES}-}programs"
|
|
615
|
-
[[
|
|
616
|
+
[[ $FIX_ERRORS -eq 1 ]] && _LOG_MODES="${_LOG_MODES:+${_LOG_MODES}-}errors"
|
|
617
|
+
[[ "$_LOG_MODES" == "wifi-health-programs-errors" ]] && _LOG_MODES="all"
|
|
616
618
|
LOG_FILE="${LOG_DIR}/fix_${_LOG_MODES}_$(date '+%Y%m%d_%H%M%S').log"
|
|
617
619
|
flog() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
|
|
618
620
|
ffix_ok() { spin_ok "$*"; flog "FIXED : $*"; FIX_COUNT=$((FIX_COUNT+1)); }
|
|
@@ -621,7 +623,7 @@ fix)
|
|
|
621
623
|
ffix_err() { spin_err "$*"; flog "ERROR : $*"; }
|
|
622
624
|
|
|
623
625
|
FIX_COUNT=0
|
|
624
|
-
flog "=== Run started | wifi=${FIX_WIFI} health=${FIX_HEALTH} programs=${FIX_PROGRAMS} ==="
|
|
626
|
+
flog "=== Run started | wifi=${FIX_WIFI} health=${FIX_HEALTH} programs=${FIX_PROGRAMS} errors=${FIX_ERRORS} ==="
|
|
625
627
|
|
|
626
628
|
banner "Auto Fix"
|
|
627
629
|
echo ""
|
|
@@ -878,6 +880,216 @@ SMBC
|
|
|
878
880
|
echo ""
|
|
879
881
|
fi
|
|
880
882
|
|
|
883
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
884
|
+
# ERRORS — journal scan, RT scheduling, permissions, PLC reach, config validity
|
|
885
|
+
# ─────────────────────────────────────────────────────────────────────────
|
|
886
|
+
if [[ $FIX_ERRORS -eq 1 ]]; then
|
|
887
|
+
echo -e " ${B}▸ Programmatic Errors${NC}"; hr; echo ""
|
|
888
|
+
|
|
889
|
+
# ── 1. Service restart / crash count ─────────────────────────────────
|
|
890
|
+
spin_start "Service stability"
|
|
891
|
+
_SVC_STABLE=1
|
|
892
|
+
for _svc in plc_watcher plc_web; do
|
|
893
|
+
_RC=$(systemctl show -p NRestarts --value "$_svc" 2>/dev/null || echo "0")
|
|
894
|
+
_RC="${_RC:-0}"
|
|
895
|
+
if [[ "$_RC" =~ ^[0-9]+$ && "$_RC" -gt 10 ]]; then
|
|
896
|
+
_spin_kill
|
|
897
|
+
ffix_warn "${_svc}: ${_RC} restarts — likely crash loop"
|
|
898
|
+
flog "WARN: ${_svc} restart count=${_RC}"
|
|
899
|
+
_SVC_STABLE=0
|
|
900
|
+
elif [[ "$_RC" =~ ^[0-9]+$ && "$_RC" -gt 3 ]]; then
|
|
901
|
+
_spin_kill
|
|
902
|
+
ffix_warn "${_svc}: ${_RC} restart(s) since last boot"
|
|
903
|
+
flog "WARN: ${_svc} restart count=${_RC}"
|
|
904
|
+
_SVC_STABLE=0
|
|
905
|
+
fi
|
|
906
|
+
done
|
|
907
|
+
[[ $_SVC_STABLE -eq 1 ]] && ffix_info "Both services stable (low restart count)"
|
|
908
|
+
|
|
909
|
+
# ── 2. Journal error scan — last 2 hours ─────────────────────────────
|
|
910
|
+
spin_start "Scanning journal for errors (last 2 h)"
|
|
911
|
+
_J_RAW=$(journalctl -u plc_watcher -u plc_web --since "2 hours ago" \
|
|
912
|
+
--no-pager -q 2>/dev/null \
|
|
913
|
+
| grep -iE \
|
|
914
|
+
'(Traceback|ImportError|ModuleNotFoundError|SyntaxError|PermissionError|FileNotFoundError|JSONDecodeError|OSError|ConnectionRefusedError|TimeoutError|CRITICAL|FATAL)' \
|
|
915
|
+
| grep -v '^-- Logs begin' \
|
|
916
|
+
| tail -30 || true)
|
|
917
|
+
|
|
918
|
+
if [[ -n "$_J_RAW" ]]; then
|
|
919
|
+
_spin_kill
|
|
920
|
+
warn "Errors found in recent journal:"
|
|
921
|
+
while IFS= read -r _line; do
|
|
922
|
+
# Trim to 110 chars for display
|
|
923
|
+
printf " ${R}│${NC} ${D}%.110s${NC}\n" "$_line"
|
|
924
|
+
flog "JOURNAL: $_line"
|
|
925
|
+
done <<< "$_J_RAW"
|
|
926
|
+
echo ""
|
|
927
|
+
|
|
928
|
+
# ── Auto-fix: missing Python module ──────────────────────────────
|
|
929
|
+
_MISSING_MOD=$(echo "$_J_RAW" \
|
|
930
|
+
| grep -oP "No module named ['\"]?\K[a-zA-Z0-9_]+" | head -1 || true)
|
|
931
|
+
if [[ -n "$_MISSING_MOD" ]]; then
|
|
932
|
+
spin_start "Auto-fix: installing missing module '${_MISSING_MOD}'"
|
|
933
|
+
if "${PYTHON}" -m pip install "${_MISSING_MOD}" -q 2>/dev/null; then
|
|
934
|
+
ffix_ok "pip installed: ${_MISSING_MOD}"
|
|
935
|
+
sudo systemctl restart plc_watcher plc_web 2>/dev/null || true
|
|
936
|
+
ffix_ok "Services restarted after module install"
|
|
937
|
+
else
|
|
938
|
+
ffix_warn "pip install failed for: ${_MISSING_MOD} — try manually"
|
|
939
|
+
fi
|
|
940
|
+
fi
|
|
941
|
+
|
|
942
|
+
# ── Auto-fix: corrupt delivery_queue.json ─────────────────────────
|
|
943
|
+
if echo "$_J_RAW" | grep -q "JSONDecodeError"; then
|
|
944
|
+
_QFILE="${DATA_DIR}/delivery_queue.json"
|
|
945
|
+
if [[ -f "$_QFILE" ]]; then
|
|
946
|
+
spin_start "Auto-fix: resetting corrupt delivery queue"
|
|
947
|
+
cp "$_QFILE" "${_QFILE}.broken.$(date +%s)" 2>/dev/null || true
|
|
948
|
+
echo "[]" > "$_QFILE"
|
|
949
|
+
ffix_ok "delivery_queue.json reset (broken copy saved)"
|
|
950
|
+
fi
|
|
951
|
+
fi
|
|
952
|
+
|
|
953
|
+
# ── Auto-fix: PermissionError on data/ files ──────────────────────
|
|
954
|
+
if echo "$_J_RAW" | grep -q "PermissionError"; then
|
|
955
|
+
spin_start "Auto-fix: correcting data/ permissions"
|
|
956
|
+
sudo chown pi:pi "${DATA_DIR}" 2>/dev/null || true
|
|
957
|
+
sudo chmod 755 "${DATA_DIR}" 2>/dev/null || true
|
|
958
|
+
sudo chown pi:pi "${DATA_DIR}"/* 2>/dev/null || true
|
|
959
|
+
sudo chmod 644 "${DATA_DIR}"/* 2>/dev/null || true
|
|
960
|
+
ffix_ok "data/ ownership set to pi:pi 755/644"
|
|
961
|
+
fi
|
|
962
|
+
|
|
963
|
+
# ── Auto-fix: FileNotFoundError on a data/ file ───────────────────
|
|
964
|
+
if echo "$_J_RAW" | grep -q "FileNotFoundError.*data"; then
|
|
965
|
+
spin_start "Auto-fix: recreating missing data files"
|
|
966
|
+
mkdir -p "${DATA_DIR}" 2>/dev/null || true
|
|
967
|
+
[[ -f "${DATA_DIR}/delivery_queue.json" ]] \
|
|
968
|
+
|| echo "[]" > "${DATA_DIR}/delivery_queue.json"
|
|
969
|
+
[[ -f "${DATA_DIR}/delivery_sent.log" ]] \
|
|
970
|
+
|| touch "${DATA_DIR}/delivery_sent.log"
|
|
971
|
+
chown pi:pi "${DATA_DIR}"/* 2>/dev/null || true
|
|
972
|
+
ffix_ok "Missing data files recreated"
|
|
973
|
+
fi
|
|
974
|
+
|
|
975
|
+
else
|
|
976
|
+
ffix_info "No Python exceptions in recent logs"
|
|
977
|
+
fi
|
|
978
|
+
|
|
979
|
+
# ── 3. RT scheduling verification ─────────────────────────────────────
|
|
980
|
+
spin_start "RT scheduling (plc_watcher)"
|
|
981
|
+
_WPD=$(systemctl show -p MainPID --value plc_watcher 2>/dev/null || echo "0")
|
|
982
|
+
_WPD="${_WPD//[^0-9]/}"
|
|
983
|
+
if [[ "${_WPD:-0}" -gt 0 ]]; then
|
|
984
|
+
_SCHED=$(chrt -p "$_WPD" 2>/dev/null || echo "")
|
|
985
|
+
if echo "$_SCHED" | grep -q "SCHED_FIFO"; then
|
|
986
|
+
_PRIO=$(echo "$_SCHED" | grep -oP 'priority: \K\d+' || echo "?")
|
|
987
|
+
_AFF=$(taskset -cp "$_WPD" 2>/dev/null | grep -oP 'list: \K.*' || echo "?")
|
|
988
|
+
ffix_info "SCHED_FIFO:${_PRIO} cpus:${_AFF} pid:${_WPD}"
|
|
989
|
+
flog "INFO: plc_watcher SCHED_FIFO:${_PRIO} cpu:${_AFF}"
|
|
990
|
+
else
|
|
991
|
+
ffix_warn "RT scheduling not active — reloading unit and restarting"
|
|
992
|
+
flog "WARN: plc_watcher not SCHED_FIFO: ${_SCHED}"
|
|
993
|
+
sudo systemctl daemon-reload 2>/dev/null || true
|
|
994
|
+
sudo systemctl restart plc_watcher 2>/dev/null && ffix_ok "Service restarted" || ffix_err "Restart failed"
|
|
995
|
+
fi
|
|
996
|
+
else
|
|
997
|
+
ffix_warn "plc_watcher not running — cannot check RT scheduling"
|
|
998
|
+
fi
|
|
999
|
+
|
|
1000
|
+
# ── 4. data/ directory writability ────────────────────────────────────
|
|
1001
|
+
spin_start "data/ directory"
|
|
1002
|
+
if [[ ! -d "${DATA_DIR}" ]]; then
|
|
1003
|
+
sudo mkdir -p "${DATA_DIR}" 2>/dev/null || true
|
|
1004
|
+
sudo chown pi:pi "${DATA_DIR}" && sudo chmod 755 "${DATA_DIR}"
|
|
1005
|
+
ffix_ok "Created missing data/"
|
|
1006
|
+
elif [[ ! -w "${DATA_DIR}" ]]; then
|
|
1007
|
+
sudo chown pi:pi "${DATA_DIR}" && sudo chmod 755 "${DATA_DIR}"
|
|
1008
|
+
ffix_ok "Fixed data/ permissions (was not writable by pi)"
|
|
1009
|
+
flog "FIXED: data/ was not writable — corrected to pi:pi 755"
|
|
1010
|
+
else
|
|
1011
|
+
ffix_info "data/ writable by pi"
|
|
1012
|
+
fi
|
|
1013
|
+
|
|
1014
|
+
# ── 5. smb_config.py syntax ───────────────────────────────────────────
|
|
1015
|
+
spin_start "smb_config.py syntax"
|
|
1016
|
+
if [[ -f "${SMB_CFG}" ]]; then
|
|
1017
|
+
_SMB_ERR=$("${PYTHON}" -c "import ast; ast.parse(open('${SMB_CFG}').read())" 2>&1 || true)
|
|
1018
|
+
if [[ -n "${_SMB_ERR}" ]]; then
|
|
1019
|
+
flog "ERROR: smb_config.py syntax: ${_SMB_ERR}"
|
|
1020
|
+
ffix_warn "smb_config.py has syntax errors — resetting to disabled"
|
|
1021
|
+
printf 'SMB_ENABLED = False\nSMB_HOST = ""\nSMB_SHARE = "Reports"\nSMB_USERNAME = ""\nSMB_PASSWORD = ""\nSMB_SUBDIR = ""\n' \
|
|
1022
|
+
> "${SMB_CFG}" 2>/dev/null || true
|
|
1023
|
+
ffix_ok "smb_config.py reset — run: plc_checkweigher smb-config"
|
|
1024
|
+
else
|
|
1025
|
+
_SMB_EN=$(grep "^SMB_ENABLED" "${SMB_CFG}" 2>/dev/null \
|
|
1026
|
+
| grep -qi "true" && echo "enabled" || echo "disabled")
|
|
1027
|
+
_SMB_H=$(smb_get "SMB_HOST")
|
|
1028
|
+
ffix_info "smb_config.py valid (SMB: ${_SMB_EN}${_SMB_H:+ → ${_SMB_H}})"
|
|
1029
|
+
fi
|
|
1030
|
+
else
|
|
1031
|
+
ffix_warn "smb_config.py missing — run: plc_checkweigher smb-config"
|
|
1032
|
+
flog "WARN: smb_config.py not found at ${SMB_CFG}"
|
|
1033
|
+
fi
|
|
1034
|
+
|
|
1035
|
+
# ── 6. Source file protection (root:root 644) ─────────────────────────
|
|
1036
|
+
spin_start "Source file protection"
|
|
1037
|
+
_WRONG=$(find "${INSTALL_DIR}" -maxdepth 1 -name "*.py" \
|
|
1038
|
+
! -user root 2>/dev/null | wc -l || echo 0)
|
|
1039
|
+
if [[ "${_WRONG:-0}" -gt 0 ]]; then
|
|
1040
|
+
ffix_warn "${_WRONG} source .py file(s) not root-owned — locking"
|
|
1041
|
+
flog "WARN: ${_WRONG} source file(s) had wrong owner"
|
|
1042
|
+
sudo find "${INSTALL_DIR}" -maxdepth 1 -name "*.py" \
|
|
1043
|
+
-exec chown root:root {} \; -exec chmod 644 {} \; 2>/dev/null || true
|
|
1044
|
+
sudo find "${INSTALL_DIR}/web" -name "*.py" \
|
|
1045
|
+
-exec chown root:root {} \; -exec chmod 644 {} \; 2>/dev/null || true
|
|
1046
|
+
ffix_ok "Source files re-locked to root:root 644"
|
|
1047
|
+
else
|
|
1048
|
+
ffix_info "Source files protected (root:root 644)"
|
|
1049
|
+
fi
|
|
1050
|
+
|
|
1051
|
+
# ── 7. PLC TCP reachability ───────────────────────────────────────────
|
|
1052
|
+
spin_start "PLC TCP connection (192.168.3.250:1025)"
|
|
1053
|
+
if timeout 3 bash -c "echo >/dev/tcp/192.168.3.250/1025" 2>/dev/null; then
|
|
1054
|
+
ffix_info "PLC reachable at 192.168.3.250:1025"
|
|
1055
|
+
else
|
|
1056
|
+
ffix_warn "PLC not reachable at 192.168.3.250:1025"
|
|
1057
|
+
flog "WARN: PLC TCP connect failed (192.168.3.250:1025)"
|
|
1058
|
+
echo ""
|
|
1059
|
+
info "Possible causes:"
|
|
1060
|
+
info " • eth0 cable unplugged (check: ip link show eth0)"
|
|
1061
|
+
info " • PLC powered off / not ready"
|
|
1062
|
+
info " • SLMP not enabled in GX Works (Enable SLMP TCP port 1025)"
|
|
1063
|
+
info " • Wrong subnet on eth0 (should be 192.168.3.x)"
|
|
1064
|
+
echo ""
|
|
1065
|
+
fi
|
|
1066
|
+
|
|
1067
|
+
# ── 8. plc_live.json staleness ────────────────────────────────────────
|
|
1068
|
+
spin_start "Live state file (/tmp/plc_live.json)"
|
|
1069
|
+
if [[ -f "/tmp/plc_live.json" ]]; then
|
|
1070
|
+
_AGE=$(( $(date +%s) - $(stat -c %Y /tmp/plc_live.json 2>/dev/null || echo 0) ))
|
|
1071
|
+
if [[ "${_AGE:-0}" -gt 10 ]]; then
|
|
1072
|
+
ffix_warn "plc_live.json is ${_AGE}s old — watcher may be stuck or offline"
|
|
1073
|
+
flog "WARN: plc_live.json stale (${_AGE}s old)"
|
|
1074
|
+
else
|
|
1075
|
+
ffix_info "plc_live.json updated ${_AGE}s ago (OK)"
|
|
1076
|
+
fi
|
|
1077
|
+
else
|
|
1078
|
+
ffix_info "plc_live.json absent (normal — created when watcher connects)"
|
|
1079
|
+
fi
|
|
1080
|
+
|
|
1081
|
+
# ── 9. reader script path ─────────────────────────────────────────────
|
|
1082
|
+
spin_start "plc_reader.py present"
|
|
1083
|
+
if [[ ! -f "${INSTALL_DIR}/plc_reader.py" ]]; then
|
|
1084
|
+
ffix_err "plc_reader.py missing — watcher cannot launch it"
|
|
1085
|
+
flog "ERROR: plc_reader.py not found at ${INSTALL_DIR}/plc_reader.py"
|
|
1086
|
+
else
|
|
1087
|
+
ffix_info "plc_reader.py present and readable"
|
|
1088
|
+
fi
|
|
1089
|
+
|
|
1090
|
+
echo ""
|
|
1091
|
+
fi
|
|
1092
|
+
|
|
881
1093
|
# ── Summary ───────────────────────────────────────────────────────────────
|
|
882
1094
|
flog "=== Complete: ${FIX_COUNT} fix(es) applied ==="
|
|
883
1095
|
hr
|
|
@@ -914,6 +1126,132 @@ SMBC
|
|
|
914
1126
|
echo ""
|
|
915
1127
|
;;
|
|
916
1128
|
|
|
1129
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
1130
|
+
# UPDATE — pull latest code from GitHub, re-lock files, restart services
|
|
1131
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
1132
|
+
update)
|
|
1133
|
+
banner "System Update"
|
|
1134
|
+
echo ""
|
|
1135
|
+
need_sudo
|
|
1136
|
+
|
|
1137
|
+
# ── Warn if a batch is actively running ───────────────────────────────────
|
|
1138
|
+
_IS_RUNNING=0
|
|
1139
|
+
if [[ -f "/tmp/plc_live.json" ]]; then
|
|
1140
|
+
_RUN_VAL=$("${PYTHON}" -c \
|
|
1141
|
+
"import json; d=json.load(open('/tmp/plc_live.json')); print(d.get('running',False))" \
|
|
1142
|
+
2>/dev/null || echo "False")
|
|
1143
|
+
[[ "$_RUN_VAL" == "True" ]] && _IS_RUNNING=1
|
|
1144
|
+
fi
|
|
1145
|
+
|
|
1146
|
+
if [[ $_IS_RUNNING -eq 1 ]]; then
|
|
1147
|
+
warn "A batch is currently RUNNING on the PLC."
|
|
1148
|
+
warn "The update will stop the current batch — any unsaved data will be lost."
|
|
1149
|
+
echo ""
|
|
1150
|
+
read -r -p " Continue anyway? [y/N]: " _UPD_CONT </dev/tty
|
|
1151
|
+
_UPD_CONT="${_UPD_CONT:-N}"
|
|
1152
|
+
[[ "${_UPD_CONT^^}" == "Y" ]] || { echo " Update cancelled."; exit 0; }
|
|
1153
|
+
echo ""
|
|
1154
|
+
fi
|
|
1155
|
+
|
|
1156
|
+
# ── Network reachability ──────────────────────────────────────────────────
|
|
1157
|
+
spin_start "Checking connectivity"
|
|
1158
|
+
if ! ping -c 1 -W 3 8.8.8.8 &>/dev/null && ! ping -c 1 -W 3 github.com &>/dev/null; then
|
|
1159
|
+
spin_err "No internet connection — cannot pull updates"
|
|
1160
|
+
exit 1
|
|
1161
|
+
fi
|
|
1162
|
+
spin_ok "Network reachable"
|
|
1163
|
+
|
|
1164
|
+
# ── Snapshot current commit ───────────────────────────────────────────────
|
|
1165
|
+
_GIT="sudo git -c safe.directory=${INSTALL_DIR} -C ${INSTALL_DIR}"
|
|
1166
|
+
_PREV_HASH=$(${_GIT} rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
1167
|
+
_PREV_SHORT="${_PREV_HASH:0:7}"
|
|
1168
|
+
|
|
1169
|
+
# ── Pull ──────────────────────────────────────────────────────────────────
|
|
1170
|
+
spin_start "Pulling latest code from GitHub"
|
|
1171
|
+
_PULL_OUT=$(${_GIT} pull origin main 2>&1 || echo "GIT_FAILED")
|
|
1172
|
+
|
|
1173
|
+
if echo "$_PULL_OUT" | grep -qE "^GIT_FAILED|^error:|^fatal:"; then
|
|
1174
|
+
spin_err "git pull failed"
|
|
1175
|
+
echo "$_PULL_OUT" | head -6 | sed 's/^/ /'
|
|
1176
|
+
exit 1
|
|
1177
|
+
fi
|
|
1178
|
+
|
|
1179
|
+
_NEW_HASH=$(${_GIT} rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
1180
|
+
_NEW_SHORT="${_NEW_HASH:0:7}"
|
|
1181
|
+
|
|
1182
|
+
if [[ "$_PREV_HASH" == "$_NEW_HASH" ]]; then
|
|
1183
|
+
spin_ok "Already up to date (${_PREV_SHORT})"
|
|
1184
|
+
echo ""
|
|
1185
|
+
info "No changes pulled — services not restarted."
|
|
1186
|
+
echo ""
|
|
1187
|
+
exit 0
|
|
1188
|
+
fi
|
|
1189
|
+
spin_ok "Pulled ${_PREV_SHORT} → ${_NEW_SHORT}"
|
|
1190
|
+
|
|
1191
|
+
# ── Show what changed ─────────────────────────────────────────────────────
|
|
1192
|
+
echo ""
|
|
1193
|
+
info "Changes:"
|
|
1194
|
+
${_GIT} log --oneline "${_PREV_HASH}..HEAD" 2>/dev/null \
|
|
1195
|
+
| sed 's/^/ /' | head -15
|
|
1196
|
+
echo ""
|
|
1197
|
+
|
|
1198
|
+
# ── Re-lock source files (root:root 644) ──────────────────────────────────
|
|
1199
|
+
spin_start "Re-locking source file permissions"
|
|
1200
|
+
sudo find "${INSTALL_DIR}" -maxdepth 1 -name "*.py" \
|
|
1201
|
+
-exec chown root:root {} \; -exec chmod 644 {} \; 2>/dev/null || true
|
|
1202
|
+
sudo find "${INSTALL_DIR}/web" -name "*.py" \
|
|
1203
|
+
-exec chown root:root {} \; -exec chmod 644 {} \; 2>/dev/null || true
|
|
1204
|
+
sudo chown root:root "${INSTALL_DIR}/bin/plc_checkweigher" 2>/dev/null && \
|
|
1205
|
+
sudo chmod 755 "${INSTALL_DIR}/bin/plc_checkweigher" 2>/dev/null || true
|
|
1206
|
+
# Keep data/ writable by pi
|
|
1207
|
+
sudo chown -R pi:pi "${DATA_DIR}" 2>/dev/null || true
|
|
1208
|
+
sudo chmod 755 "${DATA_DIR}" 2>/dev/null || true
|
|
1209
|
+
spin_ok "Source files locked (root:root 644)"
|
|
1210
|
+
|
|
1211
|
+
# ── Install updated CLI to /usr/local/bin/ ────────────────────────────────
|
|
1212
|
+
spin_start "Installing updated CLI (/usr/local/bin/plc_checkweigher)"
|
|
1213
|
+
if sudo cp "${INSTALL_DIR}/bin/plc_checkweigher" /usr/local/bin/plc_checkweigher \
|
|
1214
|
+
&& sudo chmod 755 /usr/local/bin/plc_checkweigher; then
|
|
1215
|
+
spin_ok "CLI updated"
|
|
1216
|
+
else
|
|
1217
|
+
spin_warn "CLI install failed — still running previous version until next install"
|
|
1218
|
+
fi
|
|
1219
|
+
|
|
1220
|
+
# ── Update systemd unit files if they changed ─────────────────────────────
|
|
1221
|
+
_UNITS_UPDATED=0
|
|
1222
|
+
for _svc_src in "${INSTALL_DIR}/plc_watcher.service" \
|
|
1223
|
+
"${INSTALL_DIR}/web/plc_web.service"; do
|
|
1224
|
+
[[ ! -f "$_svc_src" ]] && continue
|
|
1225
|
+
_svc_dst="/etc/systemd/system/$(basename "$_svc_src")"
|
|
1226
|
+
if [[ ! -f "$_svc_dst" ]] || ! diff -q "$_svc_src" "$_svc_dst" &>/dev/null; then
|
|
1227
|
+
sudo cp "$_svc_src" "$_svc_dst" 2>/dev/null && _UNITS_UPDATED=1
|
|
1228
|
+
fi
|
|
1229
|
+
done
|
|
1230
|
+
if [[ $_UNITS_UPDATED -eq 1 ]]; then
|
|
1231
|
+
spin_start "Reloading systemd (unit files changed)"
|
|
1232
|
+
sudo systemctl daemon-reload 2>/dev/null || true
|
|
1233
|
+
spin_ok "systemd reloaded"
|
|
1234
|
+
fi
|
|
1235
|
+
|
|
1236
|
+
# ── Restart services ──────────────────────────────────────────────────────
|
|
1237
|
+
spin_start "Restarting services"
|
|
1238
|
+
sudo systemctl restart plc_watcher plc_web 2>/dev/null
|
|
1239
|
+
sleep 2
|
|
1240
|
+
spin_ok "Services restarted"
|
|
1241
|
+
|
|
1242
|
+
# ── Final status ──────────────────────────────────────────────────────────
|
|
1243
|
+
echo ""
|
|
1244
|
+
_UW=$(systemctl is-active plc_watcher 2>/dev/null || echo "inactive")
|
|
1245
|
+
_UWb=$(systemctl is-active plc_web 2>/dev/null || echo "inactive")
|
|
1246
|
+
[[ "$_UW" == "active" ]] && echo -e " ${G}✓${NC} plc_watcher active" \
|
|
1247
|
+
|| echo -e " ${R}✗${NC} plc_watcher ${_UW}"
|
|
1248
|
+
[[ "$_UWb" == "active" ]] && echo -e " ${G}✓${NC} plc_web active" \
|
|
1249
|
+
|| echo -e " ${R}✗${NC} plc_web ${_UWb}"
|
|
1250
|
+
echo ""
|
|
1251
|
+
ok "Update complete (${_PREV_SHORT} → ${_NEW_SHORT})"
|
|
1252
|
+
echo ""
|
|
1253
|
+
;;
|
|
1254
|
+
|
|
917
1255
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
918
1256
|
# UNINSTALL — two modes: software-only or full drive wipe
|
|
919
1257
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1158,6 +1496,7 @@ help|--help|-h)
|
|
|
1158
1496
|
echo " fix -wifi Fix WiFi connectivity only"
|
|
1159
1497
|
echo " fix -health Fix disk, memory, time, dirs"
|
|
1160
1498
|
echo " fix -programs Fix services, packages, queue, unit files"
|
|
1499
|
+
echo " fix -errors Scan journal, verify RT/permissions/PLC/config"
|
|
1161
1500
|
echo " logs Stream live logs (plc_watcher + plc_web)"
|
|
1162
1501
|
echo " queue Show SMB pending queue and delivery ledger"
|
|
1163
1502
|
echo ""
|
|
@@ -1176,6 +1515,7 @@ help|--help|-h)
|
|
|
1176
1515
|
echo -e " ${W}Configuration${NC}"
|
|
1177
1516
|
echo " smb-config Interactively update SMB delivery target"
|
|
1178
1517
|
echo " push-test Push latest PDF to SMB target now"
|
|
1518
|
+
echo " update Pull latest code from GitHub and restart services"
|
|
1179
1519
|
echo ""
|
|
1180
1520
|
echo -e " ${W}Display${NC}"
|
|
1181
1521
|
echo " display on Enable display (start LightDM)"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plc-checkweigher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.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"
|