plc-checkweigher 1.17.0 → 1.20.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 +18 -8
- package/package.json +1 -1
- package/setup.sh +109 -21
package/bin/plc_checkweigher
CHANGED
|
@@ -6,7 +6,8 @@ set -euo pipefail
|
|
|
6
6
|
|
|
7
7
|
INSTALL_DIR="/home/pi/plc_checkweigher"
|
|
8
8
|
PYTHON="/home/pi/plc_env/bin/python3"
|
|
9
|
-
|
|
9
|
+
DATA_DIR="${INSTALL_DIR}/data"
|
|
10
|
+
SMB_CFG="${DATA_DIR}/smb_config.py"
|
|
10
11
|
|
|
11
12
|
# ── TTY detection — animations only when connected to a real terminal ─────────
|
|
12
13
|
[[ -t 1 ]] && _TTY=1 || _TTY=0
|
|
@@ -210,8 +211,8 @@ stop)
|
|
|
210
211
|
queue)
|
|
211
212
|
banner "SMB Delivery Queue"
|
|
212
213
|
echo ""
|
|
213
|
-
QUEUE="${
|
|
214
|
-
LEDGER="${
|
|
214
|
+
QUEUE="${DATA_DIR}/delivery_queue.json"
|
|
215
|
+
LEDGER="${DATA_DIR}/delivery_sent.log"
|
|
215
216
|
if [[ -f "$QUEUE" ]]; then
|
|
216
217
|
COUNT=$(python3 -c "import json; d=json.load(open('$QUEUE')); print(len(d))" 2>/dev/null || echo 0)
|
|
217
218
|
if [[ "$COUNT" -eq 0 ]]; then
|
|
@@ -772,9 +773,17 @@ fix)
|
|
|
772
773
|
fi
|
|
773
774
|
|
|
774
775
|
spin_start "SMB config file"
|
|
776
|
+
mkdir -p "${DATA_DIR}" 2>/dev/null || true
|
|
775
777
|
if [[ ! -f "$SMB_CFG" ]]; then
|
|
776
778
|
printf 'SMB_ENABLED = False\nSMB_HOST = ""\nSMB_SHARE = "Reports"\nSMB_USERNAME = ""\nSMB_PASSWORD = ""\nSMB_SUBDIR = ""\n' \
|
|
777
|
-
> "$SMB_CFG" 2>/dev/null
|
|
779
|
+
> "$SMB_CFG" 2>/dev/null || sudo tee "$SMB_CFG" > /dev/null << 'SMBC'
|
|
780
|
+
SMB_ENABLED = False
|
|
781
|
+
SMB_HOST = ""
|
|
782
|
+
SMB_SHARE = "Reports"
|
|
783
|
+
SMB_USERNAME = ""
|
|
784
|
+
SMB_PASSWORD = ""
|
|
785
|
+
SMB_SUBDIR = ""
|
|
786
|
+
SMBC
|
|
778
787
|
ffix_ok "Created default smb_config.py (disabled — run: plc_checkweigher smb-config)"
|
|
779
788
|
else
|
|
780
789
|
ffix_info "smb_config.py present"
|
|
@@ -836,13 +845,14 @@ fix)
|
|
|
836
845
|
fi
|
|
837
846
|
|
|
838
847
|
spin_start "Delivery queue"
|
|
839
|
-
_QUEUE="${
|
|
848
|
+
_QUEUE="${DATA_DIR}/delivery_queue.json"
|
|
849
|
+
mkdir -p "${DATA_DIR}" 2>/dev/null || true
|
|
840
850
|
if [[ ! -f "$_QUEUE" ]]; then
|
|
841
|
-
echo "[]" > "$_QUEUE"
|
|
851
|
+
echo "[]" > "$_QUEUE" 2>/dev/null || true
|
|
842
852
|
ffix_ok "Created missing delivery_queue.json"
|
|
843
853
|
elif ! "${PYTHON}" -c "import json; json.load(open('${_QUEUE}'))" &>/dev/null 2>&1; then
|
|
844
854
|
mv "$_QUEUE" "${_QUEUE}.broken.$(date +%s)" 2>/dev/null || true
|
|
845
|
-
echo "[]" > "$_QUEUE"
|
|
855
|
+
echo "[]" > "$_QUEUE" 2>/dev/null || true
|
|
846
856
|
ffix_ok "Corrupt delivery queue reset (backup saved)"
|
|
847
857
|
else
|
|
848
858
|
ffix_info "delivery_queue.json valid"
|
|
@@ -1063,7 +1073,7 @@ uninstall)
|
|
|
1063
1073
|
# ── 9. Project code ──────────────────────────────────────────────────────
|
|
1064
1074
|
ustep "Removing project code"
|
|
1065
1075
|
if [[ -d "$INSTALL_DIR" ]]; then
|
|
1066
|
-
rm -rf "$INSTALL_DIR" && spin_ok "Removed ${INSTALL_DIR}"
|
|
1076
|
+
sudo rm -rf "$INSTALL_DIR" && spin_ok "Removed ${INSTALL_DIR}"
|
|
1067
1077
|
else
|
|
1068
1078
|
spin_ok "Already gone"
|
|
1069
1079
|
fi
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plc-checkweigher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.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
|
@@ -32,6 +32,7 @@ REPO_URL="https://github.com/Bibin-VR/plc-checkweigher.git"
|
|
|
32
32
|
REPO_BRANCH="main"
|
|
33
33
|
HOME_DIR="/home/${PI_USER}"
|
|
34
34
|
INSTALL_DIR="${HOME_DIR}/plc_checkweigher"
|
|
35
|
+
DATA_DIR="${INSTALL_DIR}/data" # pi-writable: queue, log, smb_config
|
|
35
36
|
VENV_DIR="${HOME_DIR}/plc_env"
|
|
36
37
|
REPORTS_DIR="${HOME_DIR}/reports"
|
|
37
38
|
BOOT_FW="/boot/firmware"
|
|
@@ -107,15 +108,20 @@ install_system_packages() {
|
|
|
107
108
|
# ── 2. Clone / update repo ────────────────────────────────────────────────────
|
|
108
109
|
setup_repo() {
|
|
109
110
|
step "Repository ..."
|
|
111
|
+
# Mark safe so git operations work regardless of ownership state.
|
|
112
|
+
git config --global --add safe.directory "${INSTALL_DIR}" 2>/dev/null || true
|
|
113
|
+
|
|
110
114
|
if [[ -d "${INSTALL_DIR}/.git" ]]; then
|
|
111
|
-
|
|
115
|
+
# Temporarily unlock so git can write index / pack files.
|
|
116
|
+
chown -R root:root "${INSTALL_DIR}" 2>/dev/null || true
|
|
117
|
+
git -C "${INSTALL_DIR}" pull --ff-only origin "${REPO_BRANCH}" \
|
|
112
118
|
&& ok "Repo updated → ${INSTALL_DIR}" \
|
|
113
119
|
|| warn "git pull failed — using existing files"
|
|
114
120
|
else
|
|
115
|
-
|
|
116
|
-
"${REPO_URL}" "${INSTALL_DIR}"
|
|
121
|
+
git clone --branch "${REPO_BRANCH}" "${REPO_URL}" "${INSTALL_DIR}"
|
|
117
122
|
ok "Repo cloned → ${INSTALL_DIR}"
|
|
118
123
|
fi
|
|
124
|
+
# Permissions are finalised by lock_source_files() later.
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
# ── 3. Python venv ────────────────────────────────────────────────────────────
|
|
@@ -135,6 +141,13 @@ setup_dirs() {
|
|
|
135
141
|
mkdir -p "${REPORTS_DIR}"
|
|
136
142
|
chown "${PI_USER}:${PI_USER}" "${REPORTS_DIR}"
|
|
137
143
|
ok "${REPORTS_DIR}"
|
|
144
|
+
|
|
145
|
+
# pi-writable data directory — queue, delivery log, SMB credentials live here.
|
|
146
|
+
# Source files above this directory are root-locked after install_services().
|
|
147
|
+
mkdir -p "${DATA_DIR}"
|
|
148
|
+
chown "${PI_USER}:${PI_USER}" "${DATA_DIR}"
|
|
149
|
+
chmod 755 "${DATA_DIR}"
|
|
150
|
+
ok "${DATA_DIR} (runtime data — pi-writable)"
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
# ── CLI tool — install plc_checkweigher command ───────────────────────────────
|
|
@@ -253,8 +266,8 @@ setup_smb() {
|
|
|
253
266
|
prompt SMB_HOST "Host IP address" ""
|
|
254
267
|
if [[ -z "${SMB_HOST}" ]]; then
|
|
255
268
|
warn "SMB push disabled — no host entered."
|
|
256
|
-
# Write a disabled smb_config.py
|
|
257
|
-
cat > "${
|
|
269
|
+
# Write a disabled smb_config.py to the pi-writable data/ directory.
|
|
270
|
+
cat > "${DATA_DIR}/smb_config.py" << 'EOF'
|
|
258
271
|
# SMB push disabled during setup
|
|
259
272
|
SMB_ENABLED = False
|
|
260
273
|
SMB_HOST = ""
|
|
@@ -263,7 +276,7 @@ SMB_USERNAME = ""
|
|
|
263
276
|
SMB_PASSWORD = ""
|
|
264
277
|
SMB_SUBDIR = ""
|
|
265
278
|
EOF
|
|
266
|
-
chown "${PI_USER}:${PI_USER}" "${
|
|
279
|
+
chown "${PI_USER}:${PI_USER}" "${DATA_DIR}/smb_config.py"
|
|
267
280
|
return
|
|
268
281
|
fi
|
|
269
282
|
|
|
@@ -275,8 +288,9 @@ EOF
|
|
|
275
288
|
hr
|
|
276
289
|
echo ""
|
|
277
290
|
|
|
278
|
-
# Write smb_config.py (gitignored — credentials stay off GitHub)
|
|
279
|
-
|
|
291
|
+
# Write smb_config.py to data/ (gitignored — credentials stay off GitHub).
|
|
292
|
+
# Stored in data/ so the pi user can update it via: plc_checkweigher smb-config
|
|
293
|
+
cat > "${DATA_DIR}/smb_config.py" << EOF
|
|
280
294
|
# SMB configuration — written by setup.sh, NOT committed to git.
|
|
281
295
|
SMB_ENABLED = True
|
|
282
296
|
SMB_HOST = "${SMB_HOST}"
|
|
@@ -285,8 +299,8 @@ SMB_USERNAME = "${SMB_USERNAME}"
|
|
|
285
299
|
SMB_PASSWORD = "${SMB_PASSWORD}"
|
|
286
300
|
SMB_SUBDIR = "${SMB_SUBDIR}"
|
|
287
301
|
EOF
|
|
288
|
-
chown "${PI_USER}:${PI_USER}" "${
|
|
289
|
-
ok "SMB config saved → ${
|
|
302
|
+
chown "${PI_USER}:${PI_USER}" "${DATA_DIR}/smb_config.py"
|
|
303
|
+
ok "SMB config saved → ${DATA_DIR}/smb_config.py"
|
|
290
304
|
|
|
291
305
|
# Test connectivity
|
|
292
306
|
echo -n " Testing connection to ${SMB_HOST} ..."
|
|
@@ -479,13 +493,13 @@ setup_display() {
|
|
|
479
493
|
# Start after hardware udev settles (HDMI/DSI detected) — not after network.
|
|
480
494
|
After=systemd-udev-settle.service local-fs.target acpid.socket dbus.service
|
|
481
495
|
Wants=systemd-udev-settle.service
|
|
496
|
+
# StartLimit* MUST be in [Unit] — ignored in [Service].
|
|
497
|
+
StartLimitBurst=10
|
|
498
|
+
StartLimitIntervalSec=60
|
|
482
499
|
|
|
483
500
|
[Service]
|
|
484
|
-
# Generous restart policy — display should always recover.
|
|
485
|
-
StartLimitBurst=20
|
|
486
|
-
StartLimitIntervalSec=120
|
|
487
501
|
Restart=on-failure
|
|
488
|
-
RestartSec=
|
|
502
|
+
RestartSec=5
|
|
489
503
|
|
|
490
504
|
# CPU cores 0-2 only — core 3 is reserved for SCHED_FIFO PLC process.
|
|
491
505
|
CPUAffinity=0 1 2
|
|
@@ -495,7 +509,7 @@ Nice=-5
|
|
|
495
509
|
|
|
496
510
|
LimitNOFILE=65536
|
|
497
511
|
EOF
|
|
498
|
-
ok "LightDM: CPUAffinity=0-2, Nice=-5,
|
|
512
|
+
ok "LightDM: CPUAffinity=0-2, Nice=-5, StartLimitBurst=10 in [Unit]"
|
|
499
513
|
|
|
500
514
|
# ── Fix utmpx — PAM needs /run/utmp to track sessions ───────────────────
|
|
501
515
|
cat > /etc/tmpfiles.d/utmp-fix.conf << 'EOF'
|
|
@@ -504,13 +518,33 @@ EOF
|
|
|
504
518
|
systemd-tmpfiles --create /etc/tmpfiles.d/utmp-fix.conf 2>/dev/null || true
|
|
505
519
|
ok "/run/utmp fixed (utmpx PAM session tracking)"
|
|
506
520
|
|
|
507
|
-
#
|
|
508
|
-
#
|
|
509
|
-
#
|
|
521
|
+
# ── Fix vc4-kms display driver — PREEMPT_RT EPROBE_DEFER workaround ─────
|
|
522
|
+
# On the RT kernel, vc4_hdmi defers its probe indefinitely waiting for the
|
|
523
|
+
# PCM audio component (-517 = EPROBE_DEFER). noaudio removes that dependency
|
|
524
|
+
# so the display DRM card is created on first probe attempt.
|
|
525
|
+
# hdmi_force_hotplug=1 initialises HDMI hardware even when no display is
|
|
526
|
+
# connected at boot (required for headless + Pi Connect screen sharing).
|
|
527
|
+
sed -i 's/^dtoverlay=vc4-kms-v3d$/dtoverlay=vc4-kms-v3d,noaudio/' \
|
|
528
|
+
"${BOOT_FW}/config.txt" 2>/dev/null || true
|
|
529
|
+
if ! grep -q '^hdmi_force_hotplug' "${BOOT_FW}/config.txt"; then
|
|
530
|
+
if grep -q '^\[all\]' "${BOOT_FW}/config.txt"; then
|
|
531
|
+
sed -i '/^\[all\]/a hdmi_force_hotplug=1' "${BOOT_FW}/config.txt"
|
|
532
|
+
else
|
|
533
|
+
echo "hdmi_force_hotplug=1" >> "${BOOT_FW}/config.txt"
|
|
534
|
+
fi
|
|
535
|
+
else
|
|
536
|
+
sed -i 's/^hdmi_force_hotplug=.*/hdmi_force_hotplug=1/' "${BOOT_FW}/config.txt"
|
|
537
|
+
fi
|
|
538
|
+
ok "vc4-kms-v3d,noaudio + hdmi_force_hotplug=1 (HDMI always initialised)"
|
|
539
|
+
|
|
540
|
+
# ── Enable rpi-connect user service (Pi Connect remote access) ──────────
|
|
541
|
+
loginctl enable-linger "${PI_USER}" 2>/dev/null || true
|
|
542
|
+
sudo -u "${PI_USER}" systemctl --user enable rpi-connect.service 2>/dev/null || true
|
|
543
|
+
ok "rpi-connect user service enabled (sign in with: rpi-connect signin)"
|
|
510
544
|
|
|
511
545
|
systemctl daemon-reload
|
|
512
546
|
systemctl enable lightdm.service 2>/dev/null || true
|
|
513
|
-
ok "LightDM enabled — starts on every boot
|
|
547
|
+
ok "LightDM enabled — starts on every boot"
|
|
514
548
|
}
|
|
515
549
|
|
|
516
550
|
# ── 11b. VS Code server priority ──────────────────────────────────────────────
|
|
@@ -555,6 +589,58 @@ EOF
|
|
|
555
589
|
ok "vscode-priority.service (cores 0-2, Nice=-5) — starts on every boot"
|
|
556
590
|
}
|
|
557
591
|
|
|
592
|
+
# ── 11c. Lock source files — root:root 644 (requires sudo to edit) ────────────
|
|
593
|
+
lock_source_files() {
|
|
594
|
+
step "Protecting source files ..."
|
|
595
|
+
|
|
596
|
+
# Source files: root:root 644 — readable+executable by all, editable by root only.
|
|
597
|
+
find "${INSTALL_DIR}" -maxdepth 1 -name "*.py" -exec chown root:root {} \; \
|
|
598
|
+
-exec chmod 644 {} \;
|
|
599
|
+
find "${INSTALL_DIR}/web" -name "*.py" -exec chown root:root {} \; \
|
|
600
|
+
-exec chmod 644 {} \; 2>/dev/null || true
|
|
601
|
+
find "${INSTALL_DIR}/web/templates" -name "*.html" -exec chown root:root {} \; \
|
|
602
|
+
-exec chmod 644 {} \; 2>/dev/null || true
|
|
603
|
+
find "${INSTALL_DIR}/web/static" -type f -exec chown root:root {} \; \
|
|
604
|
+
-exec chmod 644 {} \; 2>/dev/null || true
|
|
605
|
+
|
|
606
|
+
# Directories: root:root 755 — pi can list/cd but cannot create new files.
|
|
607
|
+
chown root:root "${INSTALL_DIR}"
|
|
608
|
+
chmod 755 "${INSTALL_DIR}"
|
|
609
|
+
[[ -d "${INSTALL_DIR}/web" ]] && chown root:root "${INSTALL_DIR}/web" && chmod 755 "${INSTALL_DIR}/web"
|
|
610
|
+
[[ -d "${INSTALL_DIR}/web/templates" ]] && chown root:root "${INSTALL_DIR}/web/templates" && chmod 755 "${INSTALL_DIR}/web/templates"
|
|
611
|
+
[[ -d "${INSTALL_DIR}/web/static" ]] && chown root:root "${INSTALL_DIR}/web/static" && chmod 755 "${INSTALL_DIR}/web/static"
|
|
612
|
+
[[ -d "${INSTALL_DIR}/assets" ]] && chown root:root "${INSTALL_DIR}/assets" && chmod 755 "${INSTALL_DIR}/assets"
|
|
613
|
+
[[ -d "${INSTALL_DIR}/bin" ]] && chown root:root "${INSTALL_DIR}/bin" && chmod 755 "${INSTALL_DIR}/bin"
|
|
614
|
+
|
|
615
|
+
# service files and scripts: root:root, readable
|
|
616
|
+
find "${INSTALL_DIR}" -maxdepth 2 -name "*.service" -exec chown root:root {} \; \
|
|
617
|
+
-exec chmod 644 {} \; 2>/dev/null || true
|
|
618
|
+
find "${INSTALL_DIR}" -maxdepth 2 -name "*.sh" -exec chown root:root {} \; \
|
|
619
|
+
-exec chmod 755 {} \; 2>/dev/null || true
|
|
620
|
+
|
|
621
|
+
# Data directory: pi-owned 755 — services write queue, log, smb_config here.
|
|
622
|
+
chown "${PI_USER}:${PI_USER}" "${DATA_DIR}"
|
|
623
|
+
chmod 755 "${DATA_DIR}"
|
|
624
|
+
|
|
625
|
+
# Pre-create data files with correct ownership so pi can write on first run.
|
|
626
|
+
local queue="${DATA_DIR}/delivery_queue.json"
|
|
627
|
+
local log="${DATA_DIR}/delivery_sent.log"
|
|
628
|
+
[[ -f "${queue}" ]] || echo '[]' > "${queue}"
|
|
629
|
+
[[ -f "${log}" ]] || touch "${log}"
|
|
630
|
+
chown "${PI_USER}:${PI_USER}" "${queue}" "${log}"
|
|
631
|
+
chmod 644 "${queue}" "${log}"
|
|
632
|
+
|
|
633
|
+
# smb_config.py in data/ stays pi-owned so plc_checkweigher smb-config can update it.
|
|
634
|
+
[[ -f "${DATA_DIR}/smb_config.py" ]] && \
|
|
635
|
+
chown "${PI_USER}:${PI_USER}" "${DATA_DIR}/smb_config.py" && \
|
|
636
|
+
chmod 644 "${DATA_DIR}/smb_config.py"
|
|
637
|
+
|
|
638
|
+
ok "Source files locked (root:root 644 — sudo required to edit)"
|
|
639
|
+
ok "Data dir writable ${DATA_DIR} (queue / log / smb_config)"
|
|
640
|
+
info "To update source: sudo nano ${INSTALL_DIR}/plc_reader.py"
|
|
641
|
+
info "To update SMB: plc_checkweigher smb-config (no sudo needed)"
|
|
642
|
+
}
|
|
643
|
+
|
|
558
644
|
# ── 12. RT kernel — installed LAST so only one reboot is needed ───────────────
|
|
559
645
|
install_rt_kernel() {
|
|
560
646
|
step "PREEMPT_RT kernel (final step before reboot) ..."
|
|
@@ -614,10 +700,11 @@ do_reboot() {
|
|
|
614
700
|
banner "Setup Complete"
|
|
615
701
|
echo ""
|
|
616
702
|
PI_IP="$(hostname -I | awk '{print $1}' 2>/dev/null || echo '<pi-ip>')"
|
|
617
|
-
printf " ${G}%-32s${NC} %s\n" "
|
|
703
|
+
printf " ${G}%-32s${NC} %s\n" "Source (root-locked):" "${INSTALL_DIR}"
|
|
704
|
+
printf " ${G}%-32s${NC} %s\n" "Data (pi-writable):" "${DATA_DIR}"
|
|
618
705
|
printf " ${G}%-32s${NC} %s\n" "Python venv:" "${VENV_DIR}"
|
|
619
706
|
printf " ${G}%-32s${NC} %s\n" "Reports output:" "${REPORTS_DIR}"
|
|
620
|
-
printf " ${G}%-32s${NC} %s\n" "SMB config:" "${
|
|
707
|
+
printf " ${G}%-32s${NC} %s\n" "SMB config:" "${DATA_DIR}/smb_config.py"
|
|
621
708
|
printf " ${G}%-32s${NC} %s\n" "RT kernel:" "kernel8-rt.img (active after reboot)"
|
|
622
709
|
printf " ${G}%-32s${NC} %s\n" "Stock kernel fallback:" "kernel8-stock.img"
|
|
623
710
|
echo ""
|
|
@@ -662,6 +749,7 @@ main() {
|
|
|
662
749
|
setup_boot_logo # 10 — Plymouth: logo + "SAI SAMARTH ENGG"
|
|
663
750
|
setup_display # 11 — LightDM priority, CPU isolation, utmpx
|
|
664
751
|
setup_vscode_priority # 11b — VS Code: cores 0-2, Nice=-5
|
|
752
|
+
lock_source_files # 11c — root:root on .py, pi:pi on data/
|
|
665
753
|
install_rt_kernel # 12 — LAST, so only one reboot needed
|
|
666
754
|
do_reboot # 12 — single reboot applies everything
|
|
667
755
|
}
|