/
install.sh
460 lines (393 loc) · 12 KB
/
install.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
#!/bin/bash
set -euo pipefail
# Usage:
# curl -Lo- https://cutt.ly/install-home-portal | bash
# or
# curl -Lo- https://cutt.ly/install-home-portal | ENV_VAR=... bash -
#
# Example:
# Install Home Portal with a remote configuration
# curl -Lo- https://cutt.ly/install-home-portal | CONFIGURATION_URL=... bash -
#
# Install Home Portal and download configuration from a URL
# curl -Lo- https://cutt.ly/install-home-portal | DOWNLOAD_CONFIGURATION_URL=... bash -
#
# Update Home Portal to a specified version
# curl -Lo- https://cutt.ly/install-home-portal | UPDATE_ONLY=true HP_VERSION=v0.2.4 bash -
#
#
# Available environment variables
# - CONFIGURATION_URL=https://.....
# Using a remote configuration file.
#
# - DOWNLOAD_CONFIGURATION_URL=https://.....
# Download a remote configuration file from the url and copy to the Home Portal installation folder.
#
# - HP_VERSION=(v0.2.4|latest|master)
# Retrict the Home Portal App version number. It should be an existing release tag on Github.
# Special values:
# - "latest" - Find the latest stable release. It is the default.
# - "master" - Download the latest files from the master git branch.
#
# - NO_RESTART=true|false
# Disable restarting at the enf of installation.
#
# - UPDATE_ONLY=true|false
# Only update Home Portal application instead of installation.
#
# - SET_HOSTNAME=homeportal-1
# Set the hostname of the device
#
# - NO_ZRAM=true|false
# Disable ZRAM feature
GITHUB_REPO="home-portal/core"
TARGET_DIR="/opt/home-portal"
HP_VERSION=${HP_VERSION:-latest}
NO_RESTART=${NO_RESTART:-false}
UPDATE_ONLY=${UPDATE_ONLY:-false}
HTTP_PORT=4000
# -----------------------------------------------------------------
ARCH=$(uname -m)
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
LIME_YELLOW=$(tput setaf 190)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)
BOLD=$(tput bold)
DONE="...${GREEN}done!${NORMAL}"
SKIP="...${YELLOW}skip!${NORMAL}"
LOCKFILE_HASH=
startBanner() {
if [ "${UPDATE_ONLY}" != true ];
then
echo -e "${YELLOW}${BOLD}Installing Home Portal application...${NORMAL}"
else
echo -e "${YELLOW}${BOLD}Updating Home Portal application...${NORMAL}"
fi
}
getSystemInfo() {
echo ""
echo "${CYAN}Getting system information...${NORMAL}"
case $ARCH in
armv7*)
ARCH="arm7";;
aarch64)
ARCH="arm64";;
x86_64)
ARCH="amd64";;
esac
echo "Your device is running ${OS} on ${ARCH} CPU architecture."
}
installDependencies() {
echo ""
echo "${CYAN}Install dependencies...${NORMAL}"
sudo apt-get update --allow-releaseinfo-change
# Install unclutter
sudo apt-get install -y --fix-missing --no-install-recommends unclutter
if ! command -v node &> /dev/null
then
# Install Node.js
echo ""
echo "${CYAN}Installing Node.js...${NORMAL}"
curl -sL https://deb.nodesource.com/setup_14.x | sudo bash -
sudo apt-get install -y nodejs
echo "${DONE}"
fi
echo "Installed Node.js version: `node -v`"
echo "Installed NPM version: `npm -v`"
}
downloadRelease() {
echo ""
echo "${CYAN}Downloading Home Portal...${NORMAL}"
if [ "${HP_VERSION}" = "latest" ];
then
local release_url="https://api.github.com/repos/${GITHUB_REPO}/releases"
local latest_release=""
echo "Getting the latest release"
latest_release=$(curl -s $release_url | grep \"tag_name\" | awk 'NR==1{print $2}' | sed -n 's/\"\(.*\)\",/\1/p')
echo -e "${YELLOW}Latest Home Portal release: ${latest_release}${NORMAL}"
HP_VERSION=$latest_release
fi
DOWNLOAD_URL="https://api.github.com/repos/${GITHUB_REPO}/tarball/${HP_VERSION}"
if [ "${HP_VERSION}" = "master" ];
then
DOWNLOAD_URL="https://github.com/${GITHUB_REPO}/archive/master.tar.gz"
fi
TMP_ROOT=$(mktemp -dt home-portal-install-XXXXXX)
TMP_FILE="$TMP_ROOT/home-portal-core-${HP_VERSION}.tar.gz"
echo "Temp file: ${TMP_FILE}"
echo "Downloading from '$DOWNLOAD_URL'..."
curl -SL "$DOWNLOAD_URL" -o "$TMP_FILE"
if [ ! -f "$TMP_FILE" ]; then
echo "Failed to download $DOWNLOAD_URL ..."
exit 1
fi
echo "${DONE}"
}
installApp() {
echo "Target directory: $TARGET_DIR"
# mkdir if not exists
if [ ! -d $TARGET_DIR ]; then
sudo mkdir -p $TARGET_DIR
sudo chown $USER:$USER $TARGET_DIR
fi
if [ -f "${TARGET_DIR}/package-lock.json" ]; then
LOCKFILE_HASH=`sha256sum ${TARGET_DIR}/package-lock.json`
echo "Lockfile hash: $LOCKFILE_HASH"
fi
echo ""
echo "${CYAN}Unpacking tarball...${NORMAL}"
tar xf "$TMP_FILE" -C "$TARGET_DIR" --strip-components=1
echo "${DONE}"
local needNpmInstall=true
if [ -n "${LOCKFILE_HASH}" ]; then
local NEW_LOCKFILE_HASH=`sha256sum ${TARGET_DIR}/package-lock.json`
if [ "${LOCKFILE_HASH}" == "${NEW_LOCKFILE_HASH}" ]; then
echo "Lockfile hash matched. Skip 'npm install'"
needNpmInstall=false
fi
fi
if [ "${needNpmInstall}" = true ]; then
echo ""
echo "${CYAN}Installing NPM dependencies...${NORMAL}"
pushd $TARGET_DIR
npm i --production
popd
echo "${DONE}"
if [ -n "${DOWNLOAD_CONFIGURATION_URL:-}" ];
then
if [ ! -e "${TARGET_DIR}/configuration.yaml" ];
then
echo "Downloading Home Portal configuration from '${DOWNLOAD_CONFIGURATION_URL}'..."
curl -Ls $DOWNLOAD_CONFIGURATION_URL | sudo tee $TARGET_DIR/configuration.yaml >/dev/null
echo $DONE
else
echo "Configuration is exist. Configuration downloading skipped."
fi
fi
fi
}
registerApp() {
echo ""
echo "${CYAN}Register Home Portal as a service...${NORMAL}"
cat <<EOF >$HOME/home-portal.service
[Unit]
Description=Home Portal
After=network.target
[Service]
Environment="PORT=${HTTP_PORT}"
Environment="NODE_ENV=production"
Environment="CONFIGURATION_URL=${CONFIGURATION_URL:-}"
Type=simple
WorkingDirectory=/opt/home-portal
ExecStart=/usr/bin/npm run start:rd
Restart=on-failure
RestartSec=5
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.target
EOF
sudo mv $HOME/home-portal.service /lib/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable home-portal
echo "${DONE}"
}
autoStartWithoutDesktop() {
cat <<EOF >$HOME/.xsession
#!/bin/bash
# Disable screensaver
xset s off
# Disable black border
xset s noblank
# Disable electric save (black screen)
xset -dpms
# Chrome switches: https://peter.sh/experiments/chromium-command-line-switches/
# sleep 5
echo "Waiting for backend..."
while [[ "\$(curl -s -o /dev/null -w '%{response_code}' http://localhost:$HTTP_PORT/)" != "200" ]]; do sleep 1; echo "Waiting..."; done
openbox-session & chromium-browser --noerrdialogs --kiosk http://localhost:$HTTP_PORT?mode=local --incognito --disable-translate --disable-pinch --overscroll-history-navigation=0 --check-for-update-interval=1 --simulate-critical-update
EOF
}
autoStartWithDesktop() {
mkdir -p /home/pi/.config/lxsession/LXDE-pi
cat <<EOF >/home/pi/.config/lxsession/LXDE-pi/autostart
@lxpanel --profile LXDE-pi
@pcmanfm --desktop --profile LXDE-pi
@xset s off
@xset -dpms
@xset s noblank
@chromium-browser --noerrdialogs --kiosk http://localhost:$HTTP_PORT?mode=local --incognito --disable-translate --disable-pinch --disable-session-crashed-bubble --overscroll-history-navigation=0 --check-for-update-interval=1 --simulate-critical-update
EOF
}
installZRAM() {
echo ""
echo "${CYAN}Installing ZRAM...${NORMAL}"
if [ -f /root/zram.sh ];
then
echo "${SKIP}"
else
cat <<EOF | sudo tee /root/zram.sh >/dev/null
#!/bin/bash
# Raspberry Pi ZRAM script
# Tuned for quad core, 1 GB RAM models
modprobe zram
echo 3 >/sys/devices/virtual/block/zram0/max_comp_streams
echo lz4 >/sys/devices/virtual/block/zram0/comp_algorithm
echo 268435456 >/sys/devices/virtual/block/zram0/mem_limit
echo 536870912 >/sys/devices/virtual/block/zram0/disksize
mkswap /dev/zram0
swapon -p 0 /dev/zram0
sysctl vm.swappiness=30
EOF
sudo chmod +x /root/zram.sh
# Install ZRAM script in crontab
if [ `sudo crontab -l | grep zram.sh | wc -l` -eq 0 ];
then
#echo "0 2 * * * /sbin/shutdown -r now" | sudo crontab
(sudo crontab -l 2>/dev/null; echo "@reboot /root/zram.sh")| sudo crontab -
fi
echo "${DONE}"
fi
}
initRaspbian() {
# Change hostname
if [ -n "${SET_HOSTNAME:-}" ];
then
#local IP=`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n 1`
#local NEWHOST=homeportal-`echo $IP | awk -F"." '{ printf $3$4 }'`
echo ""
echo "${CYAN}Change device hostname to '${SET_HOSTNAME}'...${NORMAL}"
sudo hostnamectl set-hostname ${SET_HOSTNAME}
echo "${DONE}"
fi
# Disable WiFi power saving mode
if [ `ip a |grep wlan0 | wc -l` -gt 0 ];
then
echo ""
echo "${CYAN}Disable power-save mode for wlan0...${NORMAL}"
if [ `sudo crontab -l|grep power_save |wc -l` -eq 0 ];
then
(sudo crontab -l 2>/dev/null; echo "@reboot /sbin/iw wlan0 set power_save off")| sudo crontab -
# echo "@reboot /sbin/iw wlan0 set power_save off" | sudo crontab
echo "${DONE}"
else
echo "${SKIP}"
fi
fi
echo ""
echo "${CYAN}Disable Raspbian warning messages...${NORMAL}"
# Disable lecture message
sudo touch /var/lib/sudo/lectured/pi
# Disable SSH password warning
# Credits: https://raspberrypisig.com/blog/raspbian/2019/02/26/disable-ssh-warning/
sudo rm -rf /etc/profile.d/sshpwd.sh
sudo rm -rf /etc/xdg/lxsession/LXDE-pi/sshpwd.sh
sudo rm -rf /etc/xdg/autostart/pprompt.desktop
# Disable welcome wizard
sudo rm -rf /etc/xdg/autostart/piwiz.desktop
echo "${DONE}"
# Install ZRam
if [ -z "${NO_ZRAM:-}" ];
then
installZRAM
fi
# Add Auto nightly restart
echo ""
echo "${CYAN}Add nightly restart...${NORMAL}"
if [ `sudo crontab -l|grep shutdown |wc -l` -eq 0 ];
then
#echo "0 2 * * * /sbin/shutdown -r now" | sudo crontab
(sudo crontab -l 2>/dev/null; echo "0 2 * * * /sbin/shutdown -r now")| sudo crontab -
echo "${DONE}"
else
echo "${SKIP}"
fi
# Autostart Chromium
echo ""
echo "${CYAN}Add Chromium to autostart...${NORMAL}"
autoStartWithDesktop
echo "${DONE}"
}
createVersionFile() {
echo ""
echo "${CYAN}Create VERSION file...${NORMAL}"
echo "$HP_VERSION" > $TARGET_DIR/VERSION
}
setupTerminalBanner() {
echo ""
echo "${CYAN}Create banner script...${NORMAL}"
cat <<'EOF' | sudo tee /etc/motd >/dev/null
_ _ ____ _ _
| | | | ___ _ __ ___ ___ | _ \ ___ _ __| |_ __ _| |
| |_| |/ _ \| '_ ` _ \ / _ \ | |_) / _ \| '__| __/ _` | |
| _ | (_) | | | | | | __/ | __/ (_) | | | || (_| | |
|_| |_|\___/|_| |_| |_|\___| |_| \___/|_| \__\__,_|_|
EOF
local BANNER_SCRIPT=$TARGET_DIR/banner.sh
chmod +x ${BANNER_SCRIPT}
echo ${DONE}
echo ""
echo "${CYAN}Add banner script to .profile...${NORMAL}"
PROFILE_FILE=~/.profile
if [ `cat ${PROFILE_FILE} | grep banner.sh | wc -l` = 0 ]; then
cp ${PROFILE_FILE} ${PROFILE_FILE}.bak
echo "export DISPLAY=:0.0"$'\n' >> ${PROFILE_FILE}
echo "source ${BANNER_SCRIPT}"$'\n' >> ${PROFILE_FILE}
echo ${DONE}
else
echo ${SKIP}
fi
}
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
echo -e "${RED}Failed to install Home Portal!${NORMAL}"
fi
cleanup
exit $result
}
cleanup() {
if [[ -d "${TMP_ROOT:-}" ]]; then
rm -rf "$TMP_ROOT"
fi
}
# catch errors and print help
trap "fail_trap" EXIT
finishBanner() {
echo ""
echo -e "${GREEN}${BOLD}Home Portal ${HP_VERSION} installed successfully.${NORMAL}"
if [ "${NO_RESTART}" != true ];
then
echo -e "${GREEN}${BOLD}Restarting device after 5 seconds...${NORMAL}"
sleep 5
sudo reboot
fi
}
startBanner
getSystemInfo
if [ "${UPDATE_ONLY}" != true ];
then
installDependencies
initRaspbian
fi
downloadRelease
installApp
if [ "${UPDATE_ONLY}" != true ];
then
registerApp
setupTerminalBanner
fi
cleanup
createVersionFile
finishBanner