plc-checkweigher 1.6.0 → 1.7.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 +582 -0
- package/package.json +1 -1
- package/setup.sh +20 -4
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# plc_checkweigher — CLI for the PLC Check-Weigher system
|
|
3
|
+
# Installed to /usr/local/bin/ by setup.sh
|
|
4
|
+
#
|
|
5
|
+
# Commands:
|
|
6
|
+
# status Full system diagnostic
|
|
7
|
+
# logs Live journalctl stream
|
|
8
|
+
# restart / start / stop Service control
|
|
9
|
+
# push-test Push latest PDF to SMB target
|
|
10
|
+
# queue Show SMB delivery queue + ledger
|
|
11
|
+
# wifi Scan and switch WiFi network (prompts SMB IP update)
|
|
12
|
+
# hotspot on/off/status/scan WiFi hotspot (AP mode) — direct PC connection
|
|
13
|
+
# display on/off/status Enable/disable the display (LightDM)
|
|
14
|
+
# smb-config Interactively update SMB delivery target
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
INSTALL_DIR="/home/pi/plc_checkweigher"
|
|
19
|
+
PYTHON="/home/pi/plc_env/bin/python3"
|
|
20
|
+
SMB_CFG="${INSTALL_DIR}/smb_config.py"
|
|
21
|
+
|
|
22
|
+
# ── Colours ───────────────────────────────────────────────────────────────────
|
|
23
|
+
B='\033[1;34m'; G='\033[0;32m'; R='\033[1;31m'; Y='\033[1;33m'
|
|
24
|
+
C='\033[0;36m'; D='\033[2m'; W='\033[1m'; NC='\033[0m'
|
|
25
|
+
|
|
26
|
+
ok() { echo -e " ${G}✓${NC} $*"; }
|
|
27
|
+
err() { echo -e " ${R}✗${NC} $*" >&2; }
|
|
28
|
+
warn() { echo -e " ${Y}!${NC} $*"; }
|
|
29
|
+
info() { echo -e " ${C}i${NC} $*"; }
|
|
30
|
+
hr() { echo -e " ${D}$(printf '─%.0s' {1..56})${NC}"; }
|
|
31
|
+
banner() { echo -e "\n${B} ▸ $*${NC}"; }
|
|
32
|
+
|
|
33
|
+
need_sudo() {
|
|
34
|
+
if [[ $EUID -ne 0 ]]; then
|
|
35
|
+
if ! sudo -n true 2>/dev/null; then
|
|
36
|
+
echo -e " ${Y}sudo password required${NC}"
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# ── Read current SMB config ───────────────────────────────────────────────────
|
|
42
|
+
smb_get() {
|
|
43
|
+
local key="$1"
|
|
44
|
+
grep "^${key}" "${SMB_CFG}" 2>/dev/null \
|
|
45
|
+
| head -1 | sed 's/.*= *"//;s/".*//'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
smb_set() {
|
|
49
|
+
local key="$1" val="$2"
|
|
50
|
+
if grep -q "^${key}" "${SMB_CFG}" 2>/dev/null; then
|
|
51
|
+
sed -i "s|^${key}.*|${key} = \"${val}\"|" "${SMB_CFG}"
|
|
52
|
+
else
|
|
53
|
+
echo "${key} = \"${val}\"" >> "${SMB_CFG}"
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# ── SMB config update prompt (reused by wifi + smb-config) ───────────────────
|
|
58
|
+
prompt_smb_config() {
|
|
59
|
+
local context="${1:-}"
|
|
60
|
+
echo ""
|
|
61
|
+
banner "Update SMB Delivery Config"
|
|
62
|
+
[[ -n "$context" ]] && info "$context"
|
|
63
|
+
echo ""
|
|
64
|
+
|
|
65
|
+
CUR_HOST=$(smb_get "SMB_HOST")
|
|
66
|
+
CUR_SHARE=$(smb_get "SMB_SHARE")
|
|
67
|
+
CUR_USER=$(smb_get "SMB_USERNAME")
|
|
68
|
+
CUR_PASS=$(smb_get "SMB_PASSWORD")
|
|
69
|
+
CUR_ENABLED=$(grep "^SMB_ENABLED" "${SMB_CFG}" 2>/dev/null | grep -o "True\|False" || echo "True")
|
|
70
|
+
|
|
71
|
+
hr
|
|
72
|
+
printf " ${B}%-22s${NC} ${D}current: %s${NC}\n" "Host IP" "${CUR_HOST:-(not set)}"
|
|
73
|
+
printf " ${B}%-22s${NC} ${D}current: %s${NC}\n" "Share name" "${CUR_SHARE:-(not set)}"
|
|
74
|
+
printf " ${B}%-22s${NC} ${D}current: %s${NC}\n" "Username" "${CUR_USER:-(not set)}"
|
|
75
|
+
printf " ${B}%-22s${NC} ${D}current: %s${NC}\n" "Password" "${CUR_PASS:-(not set)}"
|
|
76
|
+
hr
|
|
77
|
+
echo ""
|
|
78
|
+
|
|
79
|
+
read -r -p " Host IP [${CUR_HOST}]: " NEW_HOST </dev/tty
|
|
80
|
+
NEW_HOST="${NEW_HOST:-$CUR_HOST}"
|
|
81
|
+
|
|
82
|
+
read -r -p " Share name [${CUR_SHARE:-Reports}]: " NEW_SHARE </dev/tty
|
|
83
|
+
NEW_SHARE="${NEW_SHARE:-${CUR_SHARE:-Reports}}"
|
|
84
|
+
|
|
85
|
+
read -r -p " Username [${CUR_USER:-plcreport}]: " NEW_USER </dev/tty
|
|
86
|
+
NEW_USER="${NEW_USER:-${CUR_USER:-plcreport}}"
|
|
87
|
+
|
|
88
|
+
read -r -s -p " Password (leave blank to keep current): " NEW_PASS </dev/tty
|
|
89
|
+
echo ""
|
|
90
|
+
NEW_PASS="${NEW_PASS:-$CUR_PASS}"
|
|
91
|
+
|
|
92
|
+
# Write updated config
|
|
93
|
+
cat > "${SMB_CFG}" << EOF
|
|
94
|
+
SMB_ENABLED = True
|
|
95
|
+
SMB_HOST = "${NEW_HOST}"
|
|
96
|
+
SMB_SHARE = "${NEW_SHARE}"
|
|
97
|
+
SMB_USERNAME = "${NEW_USER}"
|
|
98
|
+
SMB_PASSWORD = "${NEW_PASS}"
|
|
99
|
+
SMB_SUBDIR = ""
|
|
100
|
+
EOF
|
|
101
|
+
|
|
102
|
+
echo ""
|
|
103
|
+
ok "smb_config.py updated"
|
|
104
|
+
info "Host: ${NEW_HOST} | Share: //${NEW_HOST}/${NEW_SHARE} | User: ${NEW_USER}"
|
|
105
|
+
|
|
106
|
+
# Quick connectivity test
|
|
107
|
+
echo ""
|
|
108
|
+
echo -n " Testing connection ..."
|
|
109
|
+
if ping -c 2 -W 2 "${NEW_HOST}" &>/dev/null; then
|
|
110
|
+
echo ""
|
|
111
|
+
ok "${NEW_HOST} reachable"
|
|
112
|
+
if smbclient "//${NEW_HOST}/${NEW_SHARE}" -U "${NEW_USER}%${NEW_PASS}" -c "ls" &>/dev/null 2>&1; then
|
|
113
|
+
ok "SMB auth OK — PDF delivery is ready"
|
|
114
|
+
else
|
|
115
|
+
warn "SMB auth failed — verify share name and credentials on the PC"
|
|
116
|
+
fi
|
|
117
|
+
else
|
|
118
|
+
echo ""
|
|
119
|
+
warn "${NEW_HOST} not reachable right now — config saved, will retry at runtime"
|
|
120
|
+
fi
|
|
121
|
+
echo ""
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
125
|
+
CMD="${1:-help}"
|
|
126
|
+
shift || true
|
|
127
|
+
|
|
128
|
+
case "$CMD" in
|
|
129
|
+
|
|
130
|
+
# ── System diagnostic ─────────────────────────────────────────────────────────
|
|
131
|
+
status|check|diag)
|
|
132
|
+
exec "${PYTHON}" "${INSTALL_DIR}/debugger.py" "$@"
|
|
133
|
+
;;
|
|
134
|
+
|
|
135
|
+
# ── Live logs ─────────────────────────────────────────────────────────────────
|
|
136
|
+
logs)
|
|
137
|
+
exec journalctl -u plc_watcher -u plc_web -f --no-pager
|
|
138
|
+
;;
|
|
139
|
+
|
|
140
|
+
# ── Service control ───────────────────────────────────────────────────────────
|
|
141
|
+
restart)
|
|
142
|
+
need_sudo
|
|
143
|
+
banner "Restarting services"
|
|
144
|
+
sudo systemctl restart plc_watcher plc_web
|
|
145
|
+
sleep 2
|
|
146
|
+
systemctl status plc_watcher plc_web --no-pager | grep -E 'Active|Main PID'
|
|
147
|
+
;;
|
|
148
|
+
start)
|
|
149
|
+
need_sudo
|
|
150
|
+
banner "Starting services"
|
|
151
|
+
sudo systemctl start plc_watcher plc_web
|
|
152
|
+
ok "plc_watcher and plc_web started"
|
|
153
|
+
;;
|
|
154
|
+
stop)
|
|
155
|
+
need_sudo
|
|
156
|
+
banner "Stopping services"
|
|
157
|
+
sudo systemctl stop plc_watcher plc_web
|
|
158
|
+
warn "Services stopped — they will restart automatically on next boot"
|
|
159
|
+
warn "To disable auto-start: sudo systemctl disable plc_watcher plc_web"
|
|
160
|
+
;;
|
|
161
|
+
|
|
162
|
+
# ── SMB queue ─────────────────────────────────────────────────────────────────
|
|
163
|
+
queue)
|
|
164
|
+
banner "SMB Delivery Queue"
|
|
165
|
+
echo ""
|
|
166
|
+
QUEUE="${INSTALL_DIR}/delivery_queue.json"
|
|
167
|
+
LEDGER="${INSTALL_DIR}/delivery_sent.log"
|
|
168
|
+
if [[ -f "$QUEUE" ]]; then
|
|
169
|
+
COUNT=$(python3 -c "import json; d=json.load(open('$QUEUE')); print(len(d))" 2>/dev/null || echo 0)
|
|
170
|
+
if [[ "$COUNT" -eq 0 ]]; then
|
|
171
|
+
ok "Queue empty — all reports delivered"
|
|
172
|
+
else
|
|
173
|
+
warn "${COUNT} file(s) pending delivery:"
|
|
174
|
+
python3 -m json.tool "$QUEUE" 2>/dev/null
|
|
175
|
+
fi
|
|
176
|
+
else
|
|
177
|
+
ok "Queue empty"
|
|
178
|
+
fi
|
|
179
|
+
echo ""
|
|
180
|
+
if [[ -f "$LEDGER" ]]; then
|
|
181
|
+
SENT=$(wc -l < "$LEDGER")
|
|
182
|
+
ok "Delivery ledger: ${SENT} file(s) sent"
|
|
183
|
+
cat "$LEDGER" | sed 's/^/ /'
|
|
184
|
+
else
|
|
185
|
+
info "No deliveries recorded yet"
|
|
186
|
+
fi
|
|
187
|
+
echo ""
|
|
188
|
+
;;
|
|
189
|
+
|
|
190
|
+
# ── Push test ─────────────────────────────────────────────────────────────────
|
|
191
|
+
push-test)
|
|
192
|
+
banner "SMB Push Test"
|
|
193
|
+
echo ""
|
|
194
|
+
LATEST=$(ls -t /home/pi/reports/*.pdf 2>/dev/null | head -1 || true)
|
|
195
|
+
if [[ -z "$LATEST" ]]; then
|
|
196
|
+
info "No PDFs found — generating one from PLC..."
|
|
197
|
+
"${PYTHON}" "${INSTALL_DIR}/plc_report.py"
|
|
198
|
+
LATEST=$(ls -t /home/pi/reports/*.pdf 2>/dev/null | head -1 || true)
|
|
199
|
+
fi
|
|
200
|
+
[[ -z "$LATEST" ]] && { err "Could not generate PDF — is PLC connected?"; exit 1; }
|
|
201
|
+
info "File: $(basename $LATEST)"
|
|
202
|
+
echo ""
|
|
203
|
+
"${PYTHON}" -c "
|
|
204
|
+
import sys, os
|
|
205
|
+
sys.path.insert(0, '${INSTALL_DIR}')
|
|
206
|
+
from pdf_push import _push_smb, _already_sent, _record_sent
|
|
207
|
+
fname = os.path.basename('$LATEST')
|
|
208
|
+
if _already_sent(fname):
|
|
209
|
+
print(f' Already delivered: {fname}')
|
|
210
|
+
print(' Delete the ledger entry to re-test:')
|
|
211
|
+
print(f' sed -i \"/{fname}/d\" ${INSTALL_DIR}/delivery_sent.log')
|
|
212
|
+
sys.exit(0)
|
|
213
|
+
ok = _push_smb('$LATEST')
|
|
214
|
+
if ok:
|
|
215
|
+
_record_sent(fname)
|
|
216
|
+
sys.exit(0 if ok else 1)
|
|
217
|
+
"
|
|
218
|
+
;;
|
|
219
|
+
|
|
220
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
221
|
+
# WIFI — scan + switch network
|
|
222
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
223
|
+
wifi)
|
|
224
|
+
SUBCMD="${1:-scan}"
|
|
225
|
+
shift || true
|
|
226
|
+
|
|
227
|
+
case "$SUBCMD" in
|
|
228
|
+
scan|"")
|
|
229
|
+
banner "WiFi Networks"
|
|
230
|
+
echo ""
|
|
231
|
+
info "Scanning ..."
|
|
232
|
+
nmcli dev wifi rescan ifname wlan0 2>/dev/null || true
|
|
233
|
+
sleep 2
|
|
234
|
+
|
|
235
|
+
mapfile -t RAW < <(
|
|
236
|
+
nmcli -t -f SSID,SIGNAL,SECURITY,IN-USE dev wifi list ifname wlan0 2>/dev/null \
|
|
237
|
+
| awk -F: '$1!=""' \
|
|
238
|
+
| sort -t: -k2 -rn \
|
|
239
|
+
| awk -F: '!seen[$1]++'
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
[[ ${#RAW[@]} -eq 0 ]] && { warn "No networks found."; exit 0; }
|
|
243
|
+
|
|
244
|
+
echo ""
|
|
245
|
+
hr
|
|
246
|
+
printf " ${B}%-4s %-28s %-8s %-10s %s${NC}\n" "#" "SSID" "Signal" "Security" ""
|
|
247
|
+
hr
|
|
248
|
+
declare -a SSIDS
|
|
249
|
+
for i in "${!RAW[@]}"; do
|
|
250
|
+
IFS=':' read -r SSID SIGNAL SECURITY INUSE <<< "${RAW[$i]}"
|
|
251
|
+
SSIDS[$i]="$SSID"
|
|
252
|
+
SIG="${SIGNAL:-0}"
|
|
253
|
+
if [[ $SIG -ge 80 ]]; then BAR="${G}▂▄▆█${NC}"
|
|
254
|
+
elif [[ $SIG -ge 60 ]]; then BAR="${G}▂▄▆ ${NC}"
|
|
255
|
+
elif [[ $SIG -ge 40 ]]; then BAR="${Y}▂▄ ${NC}"
|
|
256
|
+
else BAR="${R}▂ ${NC}"; fi
|
|
257
|
+
ACTIVE=""
|
|
258
|
+
[[ "$INUSE" == "*" ]] && ACTIVE="${G} ← connected${NC}"
|
|
259
|
+
printf " %-4s %-28s %b %3s%% %-10s%b\n" \
|
|
260
|
+
"$((i+1)))" "$SSID" "$BAR" "$SIG" "${SECURITY:---}" "$ACTIVE"
|
|
261
|
+
done
|
|
262
|
+
hr
|
|
263
|
+
printf " %-4s %s\n" "0)" "Cancel"
|
|
264
|
+
echo ""
|
|
265
|
+
|
|
266
|
+
while true; do
|
|
267
|
+
read -r -p " Choose network [1-${#RAW[@]}] or 0 to cancel: " CHOICE </dev/tty
|
|
268
|
+
[[ "$CHOICE" =~ ^[0-9]+$ ]] && \
|
|
269
|
+
[[ "$CHOICE" -ge 0 && "$CHOICE" -le "${#RAW[@]}" ]] && break
|
|
270
|
+
echo -e " ${R}Enter a number 0–${#RAW[@]}${NC}"
|
|
271
|
+
done
|
|
272
|
+
[[ "$CHOICE" -eq 0 ]] && exit 0
|
|
273
|
+
|
|
274
|
+
SEL="${SSIDS[$((CHOICE-1))]}"
|
|
275
|
+
echo ""
|
|
276
|
+
read -r -s -p " Password for '${SEL}' (blank if open): " WIFI_PASS </dev/tty
|
|
277
|
+
echo ""
|
|
278
|
+
echo ""
|
|
279
|
+
|
|
280
|
+
need_sudo
|
|
281
|
+
# Remove existing connection if any, then connect
|
|
282
|
+
sudo nmcli connection delete "$SEL" 2>/dev/null || true
|
|
283
|
+
if [[ -n "$WIFI_PASS" ]]; then
|
|
284
|
+
sudo nmcli connection add type wifi ifname wlan0 con-name "$SEL" \
|
|
285
|
+
ssid "$SEL" wifi-sec.key-mgmt wpa-psk wifi-sec.psk "$WIFI_PASS" \
|
|
286
|
+
connection.autoconnect yes connection.autoconnect-priority 200 \
|
|
287
|
+
2>/dev/null
|
|
288
|
+
else
|
|
289
|
+
sudo nmcli connection add type wifi ifname wlan0 con-name "$SEL" \
|
|
290
|
+
ssid "$SEL" connection.autoconnect yes \
|
|
291
|
+
connection.autoconnect-priority 200 2>/dev/null
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
echo -n " Connecting to '$SEL' ..."
|
|
295
|
+
if sudo nmcli connection up "$SEL" 2>/dev/null; then
|
|
296
|
+
echo ""
|
|
297
|
+
sleep 2
|
|
298
|
+
NEW_IP=$(ip -4 addr show wlan0 2>/dev/null | grep -oP '(?<=inet )\d+\.\d+\.\d+\.\d+' || echo "")
|
|
299
|
+
ok "Connected to '${SEL}'"
|
|
300
|
+
[[ -n "$NEW_IP" ]] && ok "New IP: ${NEW_IP} → web UI at http://${NEW_IP}:8080"
|
|
301
|
+
|
|
302
|
+
# Prompt to update SMB host IP
|
|
303
|
+
echo ""
|
|
304
|
+
echo -e " ${Y}Network changed — SMB delivery target may need updating.${NC}"
|
|
305
|
+
read -r -p " Update SMB host IP? [Y/n]: " CONFIRM </dev/tty
|
|
306
|
+
CONFIRM="${CONFIRM:-Y}"
|
|
307
|
+
if [[ "${CONFIRM^^}" == "Y" ]]; then
|
|
308
|
+
prompt_smb_config "Network changed to '${SEL}' (Pi IP: ${NEW_IP:-unknown})"
|
|
309
|
+
fi
|
|
310
|
+
else
|
|
311
|
+
echo ""
|
|
312
|
+
warn "Could not connect — check password and try again"
|
|
313
|
+
fi
|
|
314
|
+
;;
|
|
315
|
+
|
|
316
|
+
*)
|
|
317
|
+
echo "Usage: plc_checkweigher wifi [scan]"
|
|
318
|
+
;;
|
|
319
|
+
esac
|
|
320
|
+
;;
|
|
321
|
+
|
|
322
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
323
|
+
# HOTSPOT — AP mode for direct PC connection + SMB push
|
|
324
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
325
|
+
hotspot)
|
|
326
|
+
SUBCMD="${1:-status}"
|
|
327
|
+
shift || true
|
|
328
|
+
HOTSPOT_SSID="${HOTSPOT_SSID:-PLC-Reports}"
|
|
329
|
+
HOTSPOT_PASS="${HOTSPOT_PASS:-plcreport}"
|
|
330
|
+
HOTSPOT_CON="plc-hotspot"
|
|
331
|
+
|
|
332
|
+
case "$SUBCMD" in
|
|
333
|
+
on)
|
|
334
|
+
banner "Enable Hotspot"
|
|
335
|
+
need_sudo
|
|
336
|
+
echo ""
|
|
337
|
+
|
|
338
|
+
# Allow custom SSID/pass as args
|
|
339
|
+
[[ -n "${1:-}" ]] && HOTSPOT_SSID="$1"
|
|
340
|
+
[[ -n "${2:-}" ]] && HOTSPOT_PASS="$2"
|
|
341
|
+
|
|
342
|
+
# Bring down existing hotspot connection if any
|
|
343
|
+
sudo nmcli connection delete "$HOTSPOT_CON" 2>/dev/null || true
|
|
344
|
+
|
|
345
|
+
info "Creating hotspot '${HOTSPOT_SSID}' on wlan0 ..."
|
|
346
|
+
sudo nmcli device wifi hotspot \
|
|
347
|
+
ifname wlan0 \
|
|
348
|
+
con-name "$HOTSPOT_CON" \
|
|
349
|
+
ssid "$HOTSPOT_SSID" \
|
|
350
|
+
password "$HOTSPOT_PASS" 2>&1 | grep -v "^$" || true
|
|
351
|
+
|
|
352
|
+
sleep 2
|
|
353
|
+
|
|
354
|
+
# Get Pi's hotspot IP (usually 10.42.0.1)
|
|
355
|
+
HOTSPOT_IP=$(ip -4 addr show wlan0 2>/dev/null \
|
|
356
|
+
| grep -oP '(?<=inet )\d+\.\d+\.\d+\.\d+' || echo "10.42.0.1")
|
|
357
|
+
|
|
358
|
+
echo ""
|
|
359
|
+
ok "Hotspot active"
|
|
360
|
+
echo ""
|
|
361
|
+
echo -e " ${W}┌────────────────────────────────────────────────┐${NC}"
|
|
362
|
+
echo -e " ${W}│ Connect your PC to this WiFi: │${NC}"
|
|
363
|
+
echo -e " ${W}│ │${NC}"
|
|
364
|
+
printf " ${W}│ %-14s ${G}%-30s${W} │${NC}\n" "SSID:" "$HOTSPOT_SSID"
|
|
365
|
+
printf " ${W}│ %-14s ${G}%-30s${W} │${NC}\n" "Password:" "$HOTSPOT_PASS"
|
|
366
|
+
printf " ${W}│ %-14s ${C}%-30s${W} │${NC}\n" "Pi IP:" "$HOTSPOT_IP"
|
|
367
|
+
echo -e " ${W}└────────────────────────────────────────────────┘${NC}"
|
|
368
|
+
echo ""
|
|
369
|
+
info "After PC connects, run: plc_checkweigher hotspot scan"
|
|
370
|
+
info " — detects PC's IP and updates SMB config automatically"
|
|
371
|
+
echo ""
|
|
372
|
+
info "Web UI still accessible at: http://${HOTSPOT_IP}:8080"
|
|
373
|
+
echo ""
|
|
374
|
+
;;
|
|
375
|
+
|
|
376
|
+
off)
|
|
377
|
+
banner "Disable Hotspot"
|
|
378
|
+
need_sudo
|
|
379
|
+
sudo nmcli connection delete "$HOTSPOT_CON" 2>/dev/null \
|
|
380
|
+
&& ok "Hotspot stopped" \
|
|
381
|
+
|| warn "No active hotspot found"
|
|
382
|
+
echo ""
|
|
383
|
+
info "To reconnect to WiFi: plc_checkweigher wifi"
|
|
384
|
+
echo ""
|
|
385
|
+
;;
|
|
386
|
+
|
|
387
|
+
status)
|
|
388
|
+
banner "Hotspot Status"
|
|
389
|
+
echo ""
|
|
390
|
+
if nmcli connection show --active 2>/dev/null | grep -q "$HOTSPOT_CON"; then
|
|
391
|
+
HOTSPOT_IP=$(ip -4 addr show wlan0 2>/dev/null \
|
|
392
|
+
| grep -oP '(?<=inet )\d+\.\d+\.\d+\.\d+' || echo "?")
|
|
393
|
+
ok "Hotspot is ON"
|
|
394
|
+
info "SSID: ${HOTSPOT_SSID} | Pi IP: ${HOTSPOT_IP}"
|
|
395
|
+
info "Run: plc_checkweigher hotspot scan — to find connected PCs"
|
|
396
|
+
else
|
|
397
|
+
info "Hotspot is OFF"
|
|
398
|
+
info "Run: plc_checkweigher hotspot on — to start"
|
|
399
|
+
fi
|
|
400
|
+
echo ""
|
|
401
|
+
;;
|
|
402
|
+
|
|
403
|
+
scan)
|
|
404
|
+
# Find devices connected to the hotspot subnet and offer to set as SMB target
|
|
405
|
+
banner "Scanning for connected devices"
|
|
406
|
+
echo ""
|
|
407
|
+
|
|
408
|
+
HOTSPOT_IP=$(ip -4 addr show wlan0 2>/dev/null \
|
|
409
|
+
| grep -oP '(?<=inet )\d+\.\d+\.\d+\.\d+' || echo "")
|
|
410
|
+
|
|
411
|
+
if [[ -z "$HOTSPOT_IP" ]]; then
|
|
412
|
+
err "Hotspot not active — run: plc_checkweigher hotspot on"
|
|
413
|
+
exit 1
|
|
414
|
+
fi
|
|
415
|
+
|
|
416
|
+
SUBNET="${HOTSPOT_IP%.*}.0/24"
|
|
417
|
+
info "Scanning ${SUBNET} ..."
|
|
418
|
+
|
|
419
|
+
# Refresh ARP table by pinging the subnet
|
|
420
|
+
for i in $(seq 1 254); do
|
|
421
|
+
ping -c 1 -W 1 "${HOTSPOT_IP%.*}.${i}" &>/dev/null &
|
|
422
|
+
done
|
|
423
|
+
wait
|
|
424
|
+
sleep 1
|
|
425
|
+
|
|
426
|
+
# Collect clients (exclude Pi itself)
|
|
427
|
+
mapfile -t CLIENTS < <(
|
|
428
|
+
ip neigh show 2>/dev/null \
|
|
429
|
+
| grep "REACHABLE\|STALE\|DELAY" \
|
|
430
|
+
| grep "${HOTSPOT_IP%.*}\." \
|
|
431
|
+
| grep -v "^${HOTSPOT_IP}" \
|
|
432
|
+
| awk '{print $1}' \
|
|
433
|
+
| sort -t. -k4 -n
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
if [[ ${#CLIENTS[@]} -eq 0 ]]; then
|
|
437
|
+
warn "No devices found yet — make sure the PC is connected to '${HOTSPOT_SSID}'"
|
|
438
|
+
info "Try again in a few seconds: plc_checkweigher hotspot scan"
|
|
439
|
+
echo ""
|
|
440
|
+
exit 0
|
|
441
|
+
fi
|
|
442
|
+
|
|
443
|
+
echo ""
|
|
444
|
+
hr
|
|
445
|
+
printf " ${B}%-4s %-18s %s${NC}\n" "#" "IP Address" "Hostname"
|
|
446
|
+
hr
|
|
447
|
+
declare -a CLIENT_IPS
|
|
448
|
+
for i in "${!CLIENTS[@]}"; do
|
|
449
|
+
IP="${CLIENTS[$i]}"
|
|
450
|
+
CLIENT_IPS[$i]="$IP"
|
|
451
|
+
HOST=$(host "$IP" 2>/dev/null | grep "domain name pointer" | awk '{print $NF}' | sed 's/\.$//' || echo "")
|
|
452
|
+
printf " %-4s %-18s %s\n" "$((i+1)))" "$IP" "${HOST:-(unknown)}"
|
|
453
|
+
done
|
|
454
|
+
hr
|
|
455
|
+
printf " %-4s %s\n" "0)" "Cancel"
|
|
456
|
+
echo ""
|
|
457
|
+
|
|
458
|
+
while true; do
|
|
459
|
+
read -r -p " Set device as SMB target [1-${#CLIENTS[@]}] or 0 to cancel: " CHOICE </dev/tty
|
|
460
|
+
[[ "$CHOICE" =~ ^[0-9]+$ ]] && \
|
|
461
|
+
[[ "$CHOICE" -ge 0 && "$CHOICE" -le "${#CLIENTS[@]}" ]] && break
|
|
462
|
+
done
|
|
463
|
+
[[ "$CHOICE" -eq 0 ]] && exit 0
|
|
464
|
+
|
|
465
|
+
TARGET_IP="${CLIENT_IPS[$((CHOICE-1))]}"
|
|
466
|
+
echo ""
|
|
467
|
+
info "Selected: ${TARGET_IP}"
|
|
468
|
+
prompt_smb_config "Setting SMB target to hotspot client ${TARGET_IP}"
|
|
469
|
+
;;
|
|
470
|
+
|
|
471
|
+
*)
|
|
472
|
+
echo "Usage: plc_checkweigher hotspot [on|off|status|scan]"
|
|
473
|
+
echo " on [SSID] [PASSWORD] — start hotspot (default: PLC-Reports / plcreport)"
|
|
474
|
+
echo " off — stop hotspot"
|
|
475
|
+
echo " status — show hotspot state"
|
|
476
|
+
echo " scan — find connected PCs and set as SMB target"
|
|
477
|
+
;;
|
|
478
|
+
esac
|
|
479
|
+
;;
|
|
480
|
+
|
|
481
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
482
|
+
# DISPLAY — enable / disable LightDM
|
|
483
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
484
|
+
display)
|
|
485
|
+
SUBCMD="${1:-status}"
|
|
486
|
+
shift || true
|
|
487
|
+
|
|
488
|
+
case "$SUBCMD" in
|
|
489
|
+
on)
|
|
490
|
+
banner "Enable Display"
|
|
491
|
+
need_sudo
|
|
492
|
+
sudo systemctl start lightdm 2>/dev/null \
|
|
493
|
+
&& ok "Display enabled — LightDM started" \
|
|
494
|
+
|| warn "LightDM failed to start (may not be installed)"
|
|
495
|
+
sudo systemctl enable lightdm 2>/dev/null && ok "Auto-start enabled" || true
|
|
496
|
+
echo ""
|
|
497
|
+
;;
|
|
498
|
+
off)
|
|
499
|
+
banner "Disable Display"
|
|
500
|
+
need_sudo
|
|
501
|
+
sudo systemctl stop lightdm 2>/dev/null \
|
|
502
|
+
&& ok "Display disabled — LightDM stopped" \
|
|
503
|
+
|| warn "LightDM was not running"
|
|
504
|
+
read -r -p " Disable auto-start on boot too? [y/N]: " DIS </dev/tty
|
|
505
|
+
DIS="${DIS:-N}"
|
|
506
|
+
if [[ "${DIS^^}" == "Y" ]]; then
|
|
507
|
+
sudo systemctl disable lightdm 2>/dev/null && ok "Auto-start disabled" || true
|
|
508
|
+
fi
|
|
509
|
+
echo ""
|
|
510
|
+
;;
|
|
511
|
+
status)
|
|
512
|
+
banner "Display Status"
|
|
513
|
+
echo ""
|
|
514
|
+
ACTIVE=$(systemctl is-active lightdm 2>/dev/null || echo "inactive")
|
|
515
|
+
ENABLED=$(systemctl is-enabled lightdm 2>/dev/null || echo "disabled")
|
|
516
|
+
if [[ "$ACTIVE" == "active" ]]; then
|
|
517
|
+
ok "LightDM: RUNNING (auto-start: ${ENABLED})"
|
|
518
|
+
else
|
|
519
|
+
info "LightDM: ${ACTIVE} (auto-start: ${ENABLED})"
|
|
520
|
+
fi
|
|
521
|
+
# HDMI / display connected
|
|
522
|
+
if command -v tvservice &>/dev/null; then
|
|
523
|
+
HDMI=$(tvservice -s 2>/dev/null | head -1)
|
|
524
|
+
info "HDMI: ${HDMI}"
|
|
525
|
+
fi
|
|
526
|
+
echo ""
|
|
527
|
+
;;
|
|
528
|
+
*)
|
|
529
|
+
echo "Usage: plc_checkweigher display [on|off|status]"
|
|
530
|
+
;;
|
|
531
|
+
esac
|
|
532
|
+
;;
|
|
533
|
+
|
|
534
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
535
|
+
# SMB CONFIG — interactive update of delivery target
|
|
536
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
537
|
+
smb-config)
|
|
538
|
+
prompt_smb_config
|
|
539
|
+
;;
|
|
540
|
+
|
|
541
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
542
|
+
# HELP
|
|
543
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
544
|
+
help|--help|-h)
|
|
545
|
+
echo ""
|
|
546
|
+
echo -e "${B} plc_checkweigher${NC} — PLC Check-Weigher system CLI"
|
|
547
|
+
echo ""
|
|
548
|
+
echo -e " ${W}Diagnostics${NC}"
|
|
549
|
+
echo " status Full system diagnostic — all checks + fix hints"
|
|
550
|
+
echo " logs Stream live logs (plc_watcher + plc_web)"
|
|
551
|
+
echo " queue Show SMB pending queue and delivery ledger"
|
|
552
|
+
echo ""
|
|
553
|
+
echo -e " ${W}Services${NC}"
|
|
554
|
+
echo " start Start plc_watcher and plc_web"
|
|
555
|
+
echo " stop Stop both services"
|
|
556
|
+
echo " restart Restart both services"
|
|
557
|
+
echo ""
|
|
558
|
+
echo -e " ${W}Network${NC}"
|
|
559
|
+
echo " wifi Scan and switch WiFi network"
|
|
560
|
+
echo " hotspot on [SSID] [PASS] Start WiFi hotspot (direct PC connection)"
|
|
561
|
+
echo " hotspot off Stop hotspot"
|
|
562
|
+
echo " hotspot status Show hotspot state"
|
|
563
|
+
echo " hotspot scan Detect connected PCs → set as SMB target"
|
|
564
|
+
echo ""
|
|
565
|
+
echo -e " ${W}Configuration${NC}"
|
|
566
|
+
echo " smb-config Interactively update SMB delivery target"
|
|
567
|
+
echo " push-test Push latest PDF to SMB target now"
|
|
568
|
+
echo ""
|
|
569
|
+
echo -e " ${W}Display${NC}"
|
|
570
|
+
echo " display on Enable display (start LightDM)"
|
|
571
|
+
echo " display off Disable display (stop LightDM)"
|
|
572
|
+
echo " display status Show display state"
|
|
573
|
+
echo ""
|
|
574
|
+
;;
|
|
575
|
+
|
|
576
|
+
*)
|
|
577
|
+
err "Unknown command: $CMD"
|
|
578
|
+
echo " Run: plc_checkweigher help"
|
|
579
|
+
exit 1
|
|
580
|
+
;;
|
|
581
|
+
|
|
582
|
+
esac
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plc-checkweigher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.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
|
"bin": {
|
|
6
6
|
"plc-checkweigher": "bin/cli.js"
|
package/setup.sh
CHANGED
|
@@ -136,6 +136,21 @@ setup_dirs() {
|
|
|
136
136
|
ok "${REPORTS_DIR}"
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
# ── CLI tool — install plc_checkweigher command ───────────────────────────────
|
|
140
|
+
install_cli() {
|
|
141
|
+
step "CLI tool ..."
|
|
142
|
+
CLI_SRC="${INSTALL_DIR}/bin/plc_checkweigher"
|
|
143
|
+
CLI_DEST="/usr/local/bin/plc_checkweigher"
|
|
144
|
+
if [[ -f "${CLI_SRC}" ]]; then
|
|
145
|
+
chmod +x "${CLI_SRC}"
|
|
146
|
+
cp "${CLI_SRC}" "${CLI_DEST}"
|
|
147
|
+
ok "plc_checkweigher → ${CLI_DEST}"
|
|
148
|
+
ok "Run: plc_checkweigher status (full system diagnostic)"
|
|
149
|
+
else
|
|
150
|
+
warn "bin/plc_checkweigher not found — skipping CLI install"
|
|
151
|
+
fi
|
|
152
|
+
}
|
|
153
|
+
|
|
139
154
|
# ── 5. WiFi — scan → pick → password ─────────────────────────────────────────
|
|
140
155
|
setup_wifi() {
|
|
141
156
|
step "WiFi Setup"
|
|
@@ -601,10 +616,11 @@ main() {
|
|
|
601
616
|
setup_repo # 2
|
|
602
617
|
setup_venv # 3
|
|
603
618
|
setup_dirs # 4
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
619
|
+
install_cli # 5 — plc_checkweigher status command
|
|
620
|
+
setup_wifi # 6 — interactive WiFi picker
|
|
621
|
+
setup_smb # 7 — interactive SMB config → smb_config.py
|
|
622
|
+
setup_network_online # 8
|
|
623
|
+
install_services # 9
|
|
608
624
|
setup_boot_logo # 9 — Plymouth: logo + "SAI SAMARTH ENGG"
|
|
609
625
|
setup_display # 10 — LightDM priority, CPU isolation, utmpx, GPU
|
|
610
626
|
install_rt_kernel # 11 — LAST, so only one reboot needed
|