refactor: implements new install mechanism

This installer requires to be configured due
make config

Changes:

Add tools/configure.sh script and make config.

Refactor of uninstall.sh according to new installer

Add dev-helper.sh to provide various informations for developing
and also could check existing installation as kinda "unit-test"

This should also fix #46
and fix #41

Signed-off-by: Stephan Wendel <me@stephanwe.de>

Signed-off-by: Stephan Wendel <me@stephanwe.de>
This commit is contained in:
Stephan Wendel 2022-11-04 09:37:40 +01:00
parent ee59a12d59
commit d4a2c08152
No known key found for this signature in database
GPG Key ID: F465B83ACBA45639
23 changed files with 1203 additions and 623 deletions

3
.gitignore vendored
View File

@ -23,5 +23,6 @@ lost*
bin/rtsp-simple-server/rtsp*
bin/rtsp-simple-server/*.yml
# Ignore Custom Config for Intsaller
# Ignore Config for Intsaller
tools/config.local
tools/.config

View File

@ -1,13 +1,13 @@
#### webcamd - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
.PHONY: help install unsinstall build buildclean
.PHONY: build buildclean config help install unsinstall
# Setup
USER = $(shell whoami)
@ -25,18 +25,17 @@ help:
@echo ""
@echo " Available actions:"
@echo ""
@echo " install Installs crowsnest"
@echo " uninstall Uninstalls crowsnest"
@echo " config Configures Installer"
@echo " install Installs crowsnest (needs sudo)"
@echo " uninstall Uninstalls crowsnest (needs sudo)"
@echo " build builds binaries"
@echo " buildclean cleans binaries (for recompile)"
@echo " clean Removes Installer config"
@echo ""
install:
@bash -c 'tools/install.sh'
unattended:
@bash -c 'tools/install.sh -z'
uninstall:
@bash -c 'tools/uninstall.sh'
@ -46,4 +45,16 @@ build:
buildclean:
$(MAKE) -C $(BIN_FOLDER) clean
clean:
@if [ -f tools/.config ]; then rm -f tools/.config; fi
@echo "Removed installer config file ..."
config:
@bash -c 'tools/configure.sh'
report:
@if [ -f ~/report.txt ]; then rm -f ~/report.txt; fi
@bash -c 'tools/dev-helper.sh -a >> ~/report.txt'
@sed -ri 's/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g' ~/report.txt

View File

@ -26,7 +26,8 @@ So, this will be the 'lookout point' for your Printer.
cd ~
git clone https://github.com/mainsail-crew/crowsnest.git
cd ~/crowsnest
make install
make config
sudo make install
_This is not tested on other Distributions. If you test that on other Distributions,\
feel free to open a Pull Request to enhance Documentation._
@ -37,6 +38,7 @@ After successful Instalation you should consider to add
type: git_repo
path: ~/crowsnest
origin: https://github.com/mainsail-crew/crowsnest.git
install_script: tools/install.sh
to your moonraker.conf, to get latest and possibly greatest Features.

View File

@ -2,27 +2,33 @@
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
# crowsnest
[ -n "$CROWSNEST_CROWSNEST_REPO_SHIP" ] || CROWSNEST_CROWSNEST_REPO_SHIP=https://github.com/mainsail-crew/crowsnest.git
[ -n "$CROWSNEST_CROWSNEST_REPO_BRANCH" ] || CROWSNEST_CROWSNEST_REPO_BRANCH=master
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1
# crowsnest repo
[[ -n "$CROWSNEST_REPO_SHIP" ]] || CROWSNEST_REPO_SHIP=https://github.com/mainsail-crew/crowsnest.git
[[ -n "$CROWSNEST_REPO_BRANCH" ]] || CROWSNEST_REPO_BRANCH=master
# crowsnest setup
[[ -n "$CROWSNEST_DEFAULT_CONF" ]] || CROWSNEST_DEFAULT_CONF="resources/crowsnest.conf"
[[ -n "$CROWSNEST_CONFIG_PATH" ]] || CROWSNEST_CONFIG_PATH="/home/pi/printer_data/config"
[[ -n "$CROWSNEST_LOG_PATH" ]] || CROWSNEST_LOG_PATH="/home/pi/printer_data/logs"
[[ -n "$CROWSNEST_ENV_PATH" ]] || CROWSNEST_ENV_PATH="/home/pi/printer_data/systemd"
[[ -n "$CROWSNEST_RASPICAMFIX" ]] || CROWSNEST_RASPICAMFIX="1"
[[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ]] || CROWSNEST_ADD_CROWSNEST_MOONRAKER="1"
[[ -n "$CROWSNEST_MOONRAKER_CONF_PATH" ]] || CROWSNEST_MOONRAKER_CONF_PATH="/home/pi/printer_data/config/moonraker.conf"
# ustreamer
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \
libbsd-dev libraspberrypi-dev libgpiod-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="y"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"
[[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ]] || CROWSNEST_USTREAMER_REPO_SHIP="https://github.com/pikvm/ustreamer.git"
[[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ]] || CROWSNEST_USTREAMER_REPO_BRANCH="master"
###########################################################################
### DO NOT EDIT BELOW THIS LINE, UNLESS YOU KNOW EXACTLY WHAT HAPPENDS! ###
###########################################################################
CROWSNEST_UNATTENDED="1"

View File

@ -9,41 +9,72 @@
#### This File is distributed under GPLv3
####
# shellcheck disable=all
# shellcheck enable=requires-variable-braces
# Error handling
set -Ee
# shellcheck disable=SC1091
source /common.sh
install_cleanup_trap
echo_green "Installing crowsnest and enable webcam Service ..."
# install dependencies
# force apt update
apt update
# It could use inbuilt dependencie check, but should speed up if preinstalled.
# shellcheck disable=SC2086
check_install_pkgs ${CROWSNEST_CROWSNEST_DEPS} ${CROWSNEST_USTREAMER_DEPS}
# Move to $HOME dir
# Module only Variables
CN_BUILD_PACKAGE_FILE="/tmp/cn_packages.lst"
CN_BUILD_INSTALL_SH="/home/${BASE_USER}/crowsnest/tools/install.sh"
echo_green "Installing crowsnest ..."
## Force apt update
apt-get update
## Make sure 'git' is installed!
check_install_pkgs git
## Step 1: Move to Home Dir as WorkingDirectoy
pushd "/home/${BASE_USER}" &> /dev/null || exit 1
# make sure config folder exist
if [ ! -d "${CROWSNEST_DEFAULT_CONF_DIR}" ]; then
sudo -u "${BASE_USER}" mkdir -p "${CROWSNEST_DEFAULT_CONF_DIR}"
fi
# clone Repo
echo_green "Clone crowsnest repository ..."
gitclone CROWSNEST_CROWSNEST_REPO crowsnest
# install crowsnest - use crowsnest's make unattended
pushd "/home/${BASE_USER}/crowsnest" &> /dev/null || exit 1
echo_green "Launch crowsnest install routine ..."
pushd "/home/${BASE_USER}/crowsnest" &> /dev/null || exit 1
sudo -u "${BASE_USER}" make unattended
# Apply Raspicam fix if enabled.
if [ "${CROWSNEST_FORCE_RASPICAMFIX}" == "1" ]; then
echo -en "Applying Raspicam Fix ... \r"
sudo sh -c 'echo "bcm2835-v4l2" >> /etc/modules'
sudo cp file_templates/bcm2835-v4l2.conf /etc/modprobe.d/
echo -e "Applying Raspicam Fix ... [OK]"
fi
popd &> /dev/null || exit 1
## Step 2: clone crowsnest repo
echo_green "Clone crowsnest repository ..."
gitclone CROWSNEST_REPO crowsnest
## Step 3: grep PKGLIST from install.sh for dependencies
echo_green "Generating packages file ..."
grep "PKGLIST=" "${CN_BUILD_INSTALL_SH}" >> "${CN_BUILD_PACKAGE_FILE}"
## Step 4: Rename PKGLIST to Module usable Var
echo_green "Rename variable PKGLIST to CROWSNEST_DEPS ..."
sed -i 's/PKGLIST/CROWSNEST_DEPS/g' "${CN_BUILD_PACKAGE_FILE}"
## Step 5: Source cn_package.lst file
# shellcheck disable=SC1090
# Shellcheck has to be disabled here,
# because it is an dynamic generated file and not checkable
. "${CN_BUILD_PACKAGE_FILE}"
## Step 6: Install packages
echo_green "Install crowsnest dependencies ..."
# shellcheck disable=SC2086
# disabled because we need 'wordsplitting'
check_install_pkgs ${CROWSNEST_DEPS}
## Step 7: Move to crowsnest as working directory
pushd "/home/${BASE_USER}/crowsnest" &> /dev/null || exit 1
## Step 8: Run crowsnest install routine
echo_green "Launch crowsnest install routine ..."
make install
## Step 9: Leave crowsnest
popd &> /dev/null || exit 1
## Step 10: clean packages.lst file
rm -f "${CN_BUILD_PACKAGE_FILE}"
## Step 11: leave home dir
popd &> /dev/null || exit 1
## Step 12:
echo_green "Enable crowsnest.service ..."
systemctl_if_exists enable crowsnest.service
## Finish
echo_green "Installing crowsnest ... DONE!"

View File

@ -1,5 +1,6 @@
#### crowsnest.conf
#### This is mainsail / MainsailOS default config.
#### This is a typical default config.
#### Also used as default in mainsail / MainsailOS
#### See:
#### https://github.com/mainsail-crew/crowsnest/blob/master/README.md
#### for details to configure to your needs.
@ -20,7 +21,7 @@
[crowsnest]
log_path: ~/klipper_logs/crowsnest.log # Default logfile in ~/klipper_logs/crowsnest.log
log_path: %LOGPATH%
log_level: verbose # Valid Options are quiet/verbose/debug
delete_log: false # Deletes log on every restart, if set to true

View File

@ -1,7 +1,7 @@
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
@ -20,10 +20,11 @@ StartLimitIntervalSec=180
WantedBy=multi-user.target
[Service]
Environment=CROWSNEST_CONFIG=/home/pi/klipper_config/crowsnest.conf
Type=exec
User=pi
Type=simple
User=%USER%
RemainAfterExit=Yes
ExecStart= /usr/local/bin/crowsnest -c ${CROWSNEST_CONFIG}
WorkingDirectory=/home/%USER%/crowsnest
EnvironmentFile=%ENV%
ExecStart= /usr/local/bin/crowsnest $CROWSNEST_ARGS
Restart=on-failure
RestartSec=5

View File

@ -1,22 +1,20 @@
# crowsnest logrotate file
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
/home/pi/klipper_logs/crowsnest.log {
rotate 3
missingok
notifempty
copy
daily
dateext
dateformat .%Y-%m-%d
maxsize 4M
%LOGPATH% {
rotate 3
missingok
notifempty
copy
daily
dateext
dateformat .%Y-%m-%d
maxsize 4M
}

View File

@ -5,3 +5,4 @@ type: git_repo
path: ~/crowsnest
origin: https://github.com/mainsail-crew/crowsnest.git
managed_services: crowsnest
install_script: tools/install.sh

View File

@ -1,27 +0,0 @@
#####################################################################
#### #####
#### Information about ports and according URL's #####
#### #####
#####################################################################
#### #####
#### Port 8080 equals /webcam/?action=[stream/snapshot] #####
#### Port 8081 equals /webcam2/?action=[stream/snapshot] #####
#### Port 8082 equals /webcam3/?action=[stream/snapshot] #####
#### Port 8083 equals /webcam4/?action=[stream/snapshot] #####
#### #####
#####################################################################
[crowsnest]
log_path: ~/klipper_logs/crowsnest.log # Default logfile in ~/klipper_logs/crowsnest.log
log_level: quiet # Valid Options are quiet/verbose/debug
delete_log: true # Deletes log on every restart, if set to true
[cam 1]
mode: mjpg # mjpg/rtsp
port: 8080 # Port
device: /dev/video0 # See Log for available ...
resolution: 640x480 # widthxheight format
max_fps: 15 # If Hardware Supports this it will be forced, ohterwise ignored/coerced.

View File

@ -1,28 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=0
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \
libbsd-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

View File

@ -1,28 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=0
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \
libbsd-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

View File

@ -1,28 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg62-turbo-dev \
libbsd-dev libgpiod-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

View File

@ -1,28 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \
libbsd-dev libgpiod-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

View File

@ -1,28 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=1
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=1
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg8-dev \
libbsd-dev libraspberrypi-dev libgpiod-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="y"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

View File

@ -1,28 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
# Force Raspicam fix bool (1:yes / 0:no)
[ -n "$CROWSNEST_FORCE_RASPICAMFIX" ] || CROWSNEST_FORCE_RASPICAMFIX=0
# Add Crowsnest to moonraker.conf (update manager) bool (1:yes / 0:no)
[ -n "$CROWSNEST_ADD_CROWSNEST_MOONRAKER" ] || CROWSNEST_ADD_CROWSNEST_MOONRAKER=0
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg62-turbo-dev \
libbsd-dev libgpiod-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

View File

@ -1,25 +0,0 @@
#!/bin/bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck disable=all
# crowsnest
[ -n "$CROWSNEST_CROWSNEST_DEPS" ] || CROWSNEST_CROWSNEST_DEPS="git crudini bsdutils findutils v4l-utils ffmpeg curl \
libxcomposite1 libxtst6"
[ -n "$CROWSNEST_DEFAULT_CONF" ] || CROWSNEST_DEFAULT_CONF="mainsail_default.conf"
[ -n "$CROWSNEST_DEFAULT_CONF_DIR" ] || CROWSNEST_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config"
[ -n "$CROWSNEST_MOONRAKER_SUPPORT" ] || CROWSNEST_MOONRAKER_SUPPORT="y"
# ustreamer
[ -n "$CROWSNEST_USTREAMER_REPO_SHIP" ] || CROWSNEST_USTREAMER_REPO_SHIP=https://github.com/pikvm/ustreamer.git
[ -n "$CROWSNEST_USTREAMER_REPO_BRANCH" ] || CROWSNEST_USTREAMER_REPO_BRANCH=master
[ -n "$CROWSNEST_USTREAMER_DEPS" ] || CROWSNEST_USTREAMER_DEPS="git build-essential libevent-dev libjpeg-dev \
libbsd-dev"
[ -n "$CROWSNEST_USTREAMER_WITH_OMX" ] || CROWSNEST_USTREAMER_WITH_OMX="n"
[ -n "$CROWSNEST_USTREAMER_WITH_GPIO" ] || CROWSNEST_USTREAMER_WITH_GPIO="n"

278
tools/configure.sh Executable file
View File

@ -0,0 +1,278 @@
#!/usr/bin/env bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck enable=require-variable-braces
# Exit on errors
set -Ee
# Global Vars
CN_CONFIG_USER=$(whoami)
CN_CONFIG_CONFIGFILE="tools/.config"
CN_CONFIG_ROOTPATH="/home/${CN_CONFIG_USER}/printer_data"
CN_CONFIG_CONFIGPATH="${CN_CONFIG_ROOTPATH}/config"
CN_CONFIG_LOGPATH="${CN_CONFIG_ROOTPATH}/logs"
CN_CONFIG_ENVPATH="${CN_CONFIG_ROOTPATH}/systemd"
CN_MOONRAKER_CONFIG_PATH="${CN_CONFIG_CONFIGPATH}/moonraker.conf"
CN_USTREAMER_REPO="https://github.com/pikvm/ustreamer.git"
CN_USTREAMER_BRANCH="master"
### Messages
header_msg() {
clear
echo -e "\e[34m\n #### Crowsnest Install Configurator ####\e[0m\n"
}
welcome_msg() {
header_msg
echo -e "This will guide you through install configuration"
echo -e "After successful configuration use\n"
echo -e "\t\e[32msudo make install\e[0m\n"
echo -e "to install crowsnest ..."
}
abort_msg() {
header_msg
echo -e "Configuration aborted by user ... \e[31mExiting!\e[0m"
}
check_config_file_msg() {
header_msg
echo -e "\n\t\e[33mWarning:\e[0m Found an existing .config!\n"
}
default_path_msg() {
echo -e "Hit ENTER to use default."
}
config_path_msg() {
header_msg
echo -e "Please specify path to config file (crowsnest.conf)\n"
echo -e "\t\e[34mNOTE:\e[0m File names are hardcoded! Also skip trailing backslash!"
echo -e "\tDefault: \e[32m${CN_CONFIG_CONFIGPATH}\e[0m\n"
}
log_path_msg() {
header_msg
echo -e "Please specify path to log file (crowsnest.log)\n"
echo -e "\t\e[34mNOTE:\e[0m File names are hardcoded! Also skip trailing backslash!"
echo -e "\tDefault: \e[32m${CN_CONFIG_LOGPATH}\e[0m\n"
}
env_path_msg() {
header_msg
echo -e "Please specify path to service environment file (crowsnest.env)\n"
echo -e "\t\e[34mNOTE:\e[0m File names are hardcoded! Also skip trailing backslash!"
echo -e "\tDefault: \e[32m${CN_CONFIG_ENVPATH}\e[0m\n"
}
apply_raspicamfix_msg() {
header_msg
echo -e "Should the Raspicam Fix be applied?\n"
echo -e "\t\e[34mNOTE:\e[0m\n\tThis should be only applied if you are"
echo -e "\tusing a Raspberry Pi! This will force Raspicams"
echo -e "\tusing the device path '/dev/video0'\n"
echo -e "Available are:\n Yes [y or Y]\n No [n or N]\n Hit ENTER for auto\n"
echo -e "In 'auto' mode Installer try to detect device and applies fix if SBC is a Pi!\n"
}
add_moonraker_entry_msg() {
header_msg
echo -e "Should the update_manager entry added to your moonraker.conf?\n"
echo -e "\t\e[34mNOTE:\e[0m\n\tThis will only work if your moonraker.conf"
echo -e "\tshares the same path as your crowsnest.conf!!!\n"
echo -e "If you want/have to do that manually,\nplease see 'resources/moonraker_update.txt'"
echo -e "Copy the content in your moonraker.conf\n"
}
goodbye_msg() {
header_msg
echo -e "\t\e[32mSuccessful\e[0m configuration."
echo -e "\tIn order to install crowsnest, please run:\n"
echo -e "\t\t\e[32msudo make install\e[0m\n"
echo -e "Goodbye ..."
}
### funcs
continue_config() {
local reply
while true; do
read -erp "Continue? [Y/n]: " -i "Y" reply
case "${reply}" in
[Yy]* )
break
;;
[Nn]* )
abort_msg
exit 0
;;
* )
echo -e "\e[31mERROR: Please type Y or N !\e[0m"
;;
esac
done
}
check_config_file() {
local reply
if [[ -f "${CN_CONFIG_CONFIGFILE}" ]]; then
check_config_file_msg
while true; do
read -erp "Overwrite? [y/N]: " -i "N" reply
case "${reply}" in
[Yy]* )
rm -f tools/.config
break
;;
[Nn]* )
abort_msg
exit 0
;;
* )
echo -e "\e[31mERROR:\e[0m Please type Y or N !"
;;
esac
done
return 0
fi
return 0
}
create_config_header() {
{
echo -e "BASE_USER=\"${CN_CONFIG_USER}\"";
echo -e "CROWSNEST_USTREAMER_REPO_SHIP=\"${CN_USTREAMER_REPO}\"";
echo -e "CROWSNEST_USTREAMER_REPO_BRANCH=\"${CN_USTREAMER_BRANCH}\""
} >> "${CN_CONFIG_CONFIGFILE}"
}
specify_config_path() {
local reply
config_path_msg
default_path_msg
read -erp "Please enter path: " reply
if [[ -z "${reply}" ]]; then
echo -e "CROWSNEST_CONFIG_PATH=\"${CN_CONFIG_CONFIGPATH}\"" >> \
"${CN_CONFIG_CONFIGFILE}"
return 0
fi
if [[ -n "${reply}" ]]; then
echo -e "CROWSNEST_CONFIG_PATH=\"${reply}\"" >> "${CN_CONFIG_CONFIGFILE}"
CN_MOONRAKER_CONFIG_PATH="${reply}/moonraker.conf"
return 0
fi
}
specify_log_path() {
local reply
log_path_msg
default_path_msg
read -erp "Please enter path: " reply
if [[ -z "${reply}" ]]; then
echo -e "CROWSNEST_LOG_PATH=\"${CN_CONFIG_LOGPATH}\"" >> \
"${CN_CONFIG_CONFIGFILE}"
return 0
fi
if [[ -n "${reply}" ]]; then
echo -e "CROWSNEST_LOG_PATH=\"${reply}\"" >> "${CN_CONFIG_CONFIGFILE}"
return 0
fi
}
specify_env_path() {
local reply
env_path_msg
default_path_msg
read -erp "Please enter path: " reply
if [[ -z "${reply}" ]]; then
echo -e "CROWSNEST_ENV_PATH=\"${CN_CONFIG_ENVPATH}\"" >> \
"${CN_CONFIG_CONFIGFILE}"
return 0
fi
if [[ -n "${reply}" ]]; then
echo -e "CROWSNEST_ENV_PATH=\"${reply}\"" >> "${CN_CONFIG_CONFIGFILE}"
return 0
fi
}
apply_raspicamfix() {
local reply
apply_raspicamfix_msg
read -erp "Enable Raspicamfix?: " reply
if [[ -z "${reply}" ]]; then
echo -e "CROWSNEST_RASPICAMFIX=\"auto\"" >> \
"${CN_CONFIG_CONFIGFILE}"
return 0
fi
while true; do
case "${reply}" in
[yY]*)
echo -e "CROWSNEST_RASPICAMFIX=\"1\"" >> "${CN_CONFIG_CONFIGFILE}"
break
;;
[nN]*)
echo -e "CROWSNEST_RASPICAMFIX=\"0\"" >> "${CN_CONFIG_CONFIGFILE}"
break
;;
esac
done
}
add_moonraker_entry() {
local reply
add_moonraker_entry_msg
while true; do
read -erp "Add update_manager entry? [Y/n]: " -i "Y" reply
case "${reply}" in
[yY]*)
echo -e "CROWSNEST_ADD_CROWSNEST_MOONRAKER=\"1\"" >> "${CN_CONFIG_CONFIGFILE}"
echo "CROWSNEST_MOONRAKER_CONF_PATH=\"${CN_MOONRAKER_CONFIG_PATH}\"" \
>> "${CN_CONFIG_CONFIGFILE}"
break
;;
[nN]*)
echo -e "CROWSNEST_ADD_CROWSNEST_MOONRAKER=\"0\"" >> "${CN_CONFIG_CONFIGFILE}"
break
;;
* )
echo -e "\e[31mERROR:\e[0m Please type Y or N !"
;;
esac
done
}
### Main func
main() {
# Step 1: Welcome Message
welcome_msg
continue_config
# Step 2: Check for existing file
check_config_file
# Step 3: Create config header
create_config_header
# Step 4: Specify config file path.
specify_config_path
# Step 5: Specify log file path.
specify_log_path
# Step 6: Specify env path.
specify_env_path
# Step 7: Raspicam fix
apply_raspicamfix
# Step 8: Moonraker entry
add_moonraker_entry
# Step 9: Display finished message
goodbye_msg
}
### MAIN
main
exit 0

352
tools/dev-helper.sh Executable file
View File

@ -0,0 +1,352 @@
#!/usr/bin/env bash
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck enable=require-variable-braces
# Exit on errors
set -Ee
# Debug
# set -x
# Global Vars
TITLE="\e[31mcrowsnest\e[0m - $(basename "${0}")"
DH_VERSION="v0.0.0"
[[ -n "${BASE_USER}" ]] || BASE_USER="$(whoami)"
# Set fallback lang
export LC_ALL=C
# Message Vars
CN_OK="\e[32mOK\e[0m"
CN_FL="\e[31mFAILED\e[0m"
# leave in place for later use
# CN_SK="\e[33mSKIPPED\e[0m"
CN_G="\e[32m"
CN_R="\e[31m"
CN_B="\e[34m"
CN_N="\e[0m"
# Message funcs
echo_green() {
echo -e "\e[32m${1}\e[0m"
}
echo_red() {
echo -e "\e[31m${1}\e[0m"
}
echo_yellow() {
echo -e "\e[33m${1}\e[0m"
}
echo_blue() {
echo -e "\e[34m${1}\e[0m"
}
echo_blank() {
echo -e "\n"
}
help_msg() {
echo -e "\n\t $(basename "${0}") [Options]\n"
echo -e "\t\t-h\tPrints this help."
echo -e "\t\t-V\tShows Version of $(basename "${0}")"
echo -e "\t\t-a\tShows all available informations gathered"
echo -e "\t\t-c\tShows informations about cameras"
echo -e "\t\t-o\tShows informations about used OS"
echo -e "\t\t-s\tShows informations about host system"
echo -e "\t\t-x\tPerforms tests to ensure successful install of crowsnest"
echo -e "\t\t-d\tDecolorize file (if output is redirected to file)"
echo_blank
exit 1
}
# Global functions
## call get_os_version <keyword>
get_os_info() {
local osrel adrel
# Dirty Hack to not fail script :P
adrel="$(find /etc -name "*-release" -type f -print 2> /dev/null || echo "" )"
if [[ -f /etc/os-release ]]; then
osrel="$(grep "PRETTY_NAME=" /etc/os-release | cut -d'=' -f2 | sed 's/\"//g')"
echo_blue "OS Info:\n"
echo -e "Distribution: ${CN_G}\t${osrel}${CN_N}\n"
fi
## Find additional informations
if [[ -n "${adrel}" ]]; then
for i in ${adrel}; do
if [[ -f "${i}" ]]; then
echo_blue "Additional Release Info:\n"
echo -e "From ${i}:\n"
echo -e "${CN_G}$(cat "${i}")${CN_N}\n"
fi
done
fi
}
### Import config
import_config() {
## Source config if present
if [[ -s tools/.config ]]; then
# shellcheck disable=SC1091
source tools/.config
return 0
else
echo -e "\[31mNo .config found!\e[0m"
return 0
fi
}
is_raspberry_pi() {
if [[ -f /proc/device-tree/model ]] &&
grep -q "Raspberry" /proc/device-tree/model; then
echo "1"
else
echo "0"
fi
}
# get_val <pathtocfg> <section> <parameter>
# spits out value
get_val() {
crudini --get "${1}" "${2}" "${3}" 2> /dev/null
}
host_info() {
grep "model name" /proc/cpuinfo | head -1 | awk -F': ' '{print $2}'
}
load_avg() {
local load_avg
load_avg=$(uptime | rev | cut -d":" -f1 | rev | sed 's/ //1' )
echo " ${load_avg} (load in last 1m/5m/15m)"
}
cpu_info() {
if [[ -n "$(command -v lscpu)" ]]; then
echo_blue "CPU Details:\n"
lscpu
echo_blank
fi
}
mem_info() {
echo_blue "Mem Info:"
free -m
echo -e "\n"
}
disk_info() {
echo_blue "Disk Info:"
df -h
echo -e "\n"
}
get_host_info() {
local kernel model
kernel="$(uname -srmp)"
echo_blue "Host Informations:\n"
if [[ -f /proc/device-tree/model ]]; then
model="$(tr -d '\0' < /proc/device-tree/model)"
fi
if [[ ! -f /proc/device-tree/model ]]; then
model="${CN_R}Unknown ($(host_info))${CN_N}"
fi
echo -e "Running on: ${CN_G}${model}${CN_N}\n"
echo -e "Kernel: ${CN_G}${kernel}${CN_N}\n"
echo -e "Load Average: $(load_avg)\n"
cpu_info
mem_info
disk_info
}
get_cam_info() {
local cam ctrls vid_dev
vid_dev="$(find /dev/v4l/by-path -name "*video*index0" -print | sed '/isp/d;/codec/d' )"
if [[ -z "$(command -v v4l2-ctl)" ]]; then
echo_red "Command: v4l2-ctl not found!"
echo_red "Can not grab appropriate informations ..."
return 0
fi
## helper func
sym_lnk() {
local dev
dev="$(basename "$(readlink -f "${1}")")"
find /dev/v4l -type l -ls | grep -i "${dev}$" | awk '{print $11}'
}
echo_blue "v4l2-ctl supported camera(s):\n"
for dev in ${vid_dev}; do
cam="$(v4l2-ctl -d "${dev}" --list-formats-ext | sed '1,3d')"
ctrls="$(v4l2-ctl -d "${dev}" --list-ctrls-menus || echo "")"
echo_blue "Device $(readlink -f "${dev}"):\n"
echo_green "Symbolic links to $(readlink -f "${dev}"):\n"
sym_lnk "${dev}"
echo_blank
echo -e "Supported formats:\n"
echo -e "${cam}\n"
if [[ -n "${ctrls}" ]]; then
echo -e "Supported Controls:\n"
echo -e "${ctrls}\n"
fi
done
}
get_crowsnest() {
local cn_bin cn_svc_file
cn_bin="$(command -v crowsnest)"
cn_svc_file="$(find /etc/systemd/system -maxdepth 1 -name "crowsnest*.service")"
echo_blue "Testing install of crowsnest:\n"
echo_green "Some tests need 'sudo' rights!\nPlease enter password if prompted!\n"
sudo sh -c 'echo "" > /dev/null'
echo -e "Searching for crowsnest ..."
if [[ -n "${cn_bin}" ]]; then
echo -e "crowsnest found in ${cn_bin} [${CN_OK}]"
echo -e "\t${CN_B}==>${CN_N} $(readlink -f "${cn_bin}")\n"
echo_blue "Version:"
crowsnest -v
echo_blank
else
echo -e "crowsnest not found! [${CN_FL}]\n"
echo_red "Further test will be aborted...\n"
exit 1
fi
echo_blue "Service tests:\n"
for svc in ${cn_svc_file}; do
if [[ ! -f "${svc}" ]]; then
echo -e "${svc} not found! [${CN_FL}]\n"
fi
if [[ -f "${svc}" ]]; then
echo -e "${svc} found! [${CN_OK}]\n"
## Print service file
echo_blue "Print service file:\n"
cat -n "${svc}"
echo_blank
fi
## Check is-active
echo -e "Service Status: ${CN_G}$(sudo systemctl is-active "$(basename "${svc}")")${CN_N}\n"
## Check for env file
cn_env_path="$(grep -i "EnvironmentFile" "${svc}" | cut -d"=" -f2)"
echo_blue "Environment file ($(basename "${cn_env_path}")):"
if [[ ! -f "${cn_env_path}" ]]; then
echo -e "${cn_env_path} not found! [${CN_FL}]\n"
fi
if [[ -f "${cn_env_path}" ]]; then
echo -e "${cn_env_path} found! [${CN_OK}]\n"
echo_blue "Print environment file:\n"
cat -n "${cn_env_path}"
echo_blank
fi
## Check config file
### Import path from env file
# shellcheck disable=SC1090
. "${cn_env_path}"
cn_cnf_path="${CROWSNEST_ARGS/-c /}"
echo_blue "Config file ($(basename "${cn_cnf_path}")):"
if [[ ! -f "${cn_cnf_path}" ]]; then
echo -e "${cn_cnf_path} not found! [${CN_FL}]\n"
fi
if [[ -f "${cn_cnf_path}" ]]; then
echo -e "${cn_cnf_path} found! [${CN_OK}]\n"
echo_blue "Print config file:\n"
cat -n "${cn_cnf_path}"
echo_blank
fi
## Check log file
### Clean path
cn_log_path="$(grep -i "crowsnest.log" "${cn_cnf_path}" | sed 's#log_path: ~#'"${HOME}"'#')"
echo_blue "Log file ($(basename "${cn_log_path}")):"
if [[ ! -f "${cn_log_path}" ]]; then
echo -e "${cn_log_path} not found! [${CN_FL}]\n"
fi
if [[ -f "${cn_log_path}" ]]; then
echo -e "${cn_log_path} found! [${CN_OK}]\n"
echo_blue "Print config file (last 10 lines):\n"
tail -n10 "${cn_log_path}"
echo_blank
fi
done
}
get_config() {
echo_blue "Installer .config file ($(basename "${cn_cnf_file}")):"
cn_cnf_file="${PWD}/tools/.config"
if [[ ! -f "${cn_cnf_file}" ]]; then
echo -e "${cn_cnf_file} not found! [${CN_FL}]\n"
fi
if [[ -f "${cn_cnf_file}" ]]; then
echo -e "${cn_cnf_file} found! [${CN_OK}]\n"
echo_blue "Print .config file:\n"
cat -n "${cn_cnf_file}"
echo_blank
fi
}
decolorize() {
echo -en "Decolorizing ${1} ...\r"
sed -r -i 's/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g' "${1}"
echo -e "Decolorizing ${1} ...[${CN_OK}]\r"
echo_blank
}
#### MAIN
echo -e "${TITLE}\n"
[[ "${#}" -eq 0 ]] && help_msg
while getopts ":acd:hosxzV" arg; do
case "${arg}" in
a )
get_os_info
get_host_info
get_cam_info
get_crowsnest
get_config
break
;;
c )
get_cam_info
break
;;
d )
decolorize "${OPTARG}"
break
;;
o )
get_os_info
break
;;
s )
get_host_info
break
;;
x )
get_crowsnest
break
;;
z )
get_config
break
;;
V )
echo -e "${CN_B}$(basename "${0}")${CN_N} Version: ${CN_G}${DH_VERSION}${CN_N}\n"
break
;;
h | \? )
echo -e "Invalid option: -${OPTARG}"
help_msg
;;
esac
done
exit 0

View File

@ -1,187 +1,133 @@
#!/usr/bin/env bash
# Crow's Nest
# A multiple Cam and Stream Service for mainsailOS
# Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
# Copyright 2021 - 2022
# https://github.com/mainsail-crew/crowsnest
# GPL V3
########
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
####
# shellcheck enable=require-variable-braces
## disabled SC2086 for some lines because there we want 'word splitting'
# Exit on errors
set -Ee
# Debug
# set -x
# Global Vars
BASE_USER=$(whoami)
TITLE="crowsnest - A Webcam Daemon for Raspberry Pi OS"
TITLE="\e[31mcrowsnest\e[0m - A webcam daemon for multiple Cams and stream services."
[[ -n "${BASE_USER}" ]] || BASE_USER="$(whoami)"
[[ -n "${CROWSNEST_UNATTENDED}" ]] || CROWSNEST_UNATTENDED="0"
[[ -n "${CROWSNEST_DEFAULT_CONF}" ]] || CROWSNEST_DEFAULT_CONF="resources/crowsnest.conf"
### Non root
if [ ${UID} == '0' ]; then
echo -e "DO NOT RUN THIS SCRIPT AS ROOT!\nExiting..."
exit 1
fi
# Message Vars
CN_OK="\e[32mOK\e[0m"
CN_SK="\e[33mSKIPPED\e[0m"
### Global setup
### noninteractive Check
if [ "${DEBIAN_FRONTEND}" != "noninteractive" ]; then
if [[ "${DEBIAN_FRONTEND}" != "noninteractive" ]]; then
export DEBIAN_FRONTEND=noninteractive
fi
### Functions
### Check non-root
if [[ ${UID} != '0' ]]; then
echo -e "\n\tYOU NEED TO RUN INSTALLER AS ROOT!"
echo -e "\tPlease try '\e[32msudo make install\e[0m'\n\nExiting..."
exit 1
fi
### Global functions
### Messages
### Welcome Message
function welcome_msg {
welcome_msg() {
echo -e "${TITLE}\n"
echo -e "\tSome Parts of the Installer requires 'root' privileges."
echo -e "\tYou will be prompted for your 'sudo' password, if needed.\n"
echo -e "\t\e[34mAhoi!\e[0m"
echo -e "\tThank you for installing crowsnest ;)"
echo -e "\tThis will take a while ... "
echo -e "\tPlease reboot after installation has finished.\n"
sleep 1
}
function detect_msg {
echo -e "Found an existing 'crowsnest'. This will be removed."
echo -e "Since we dont use mjpg-streamer it will also removed."
### Config Message
config_msg() {
echo -e "\nConfig file not found!\n\tYOU NEED TO CREATE A CONFIGURATION!"
echo -e "\tPlease use 'make config' first!\nExiting..."
exit 1
}
### Detect Message
detect_msg() {
echo -e "Found an existing 'crowsnest' or mjpg-streamer"
echo -e "This has to be removed..."
echo -e "You can use KIAUH for example to reinstall.\n"
}
function goodbye_msg {
echo -e "\nInstallation complete.\n\tPlease reboot your machine!"
echo -e "I hope you enjoy crowsnest, GoodBye ..."
### Goodbye Message
goodbye_msg() {
echo -e "\nInstallation \e[32msuccessful\e[0m.\n"
echo -e "\t\e[33mTo take changes effect, you need to reboot your machine!\e[0m\n"
}
### Installer
### General
## These two functions are reused from custompios common.sh
## Credits to guysoft!
## https://github.com/guysoft/CustomPiOS
function install_cleanup_trap() {
install_cleanup_trap() {
# kills all child processes of the current process on SIGINT or SIGTERM
trap 'cleanup' SIGINT SIGTERM
}
function cleanup() {
cleanup() {
# make sure that all child processed die when we die
echo -e "Killed by user ...\r\nGoodBye ...\r"
# shellcheck disable=2046
[ -n "$(jobs -pr)" ] && kill $(jobs -pr) && sleep 5 && kill -9 $(jobs -pr)
[[ -n "$(jobs -pr)" ]] && kill "$(jobs -pr)" && sleep 5 && kill -9 "$(jobs -pr)"
}
##
function err_exit {
if [ "${1}" != "0" ]; then
err_exit() {
if [[ "${1}" != "0" ]]; then
echo -e "ERROR: Error ${1} occured on line ${2}"
echo -e "ERROR: Stopping $(basename "$0")."
echo -e "Goodbye..."
fi
# shellcheck disable=2046
[ -n "$(jobs -pr)" ] && kill $(jobs -pr) && sleep 5 && kill -9 $(jobs -pr)
[[ -n "$(jobs -pr)" ]] && kill "$(jobs -pr)" && sleep 5 && kill -9 "$(jobs -pr)"
exit 1
}
### Init ERR Trap
trap 'err_exit $? $LINENO' ERR
## helper func
## call get_os_version <keyword>
function get_os_version {
if [ -n "${1}" ]; then
get_os_version() {
if [[ -n "${1}" ]]; then
grep -c "${1}" /etc/os-release
fi
}
### Import config from custompios.
function import_config {
## Source Custom config if present
if [ -s tools/config.local ]; then
### Import config
import_config() {
## Source config if present
if [[ -s tools/.config ]]; then
# shellcheck disable=SC1091
source tools/config.local
source tools/.config
return 0
fi
## X86 machines
if [ "$(uname -m)" == "x86_64" ] &&
[ -f tools/config.x86 ]; then
# shellcheck disable=SC1091
source tools/config.x86
return 0
fi
## rpi os buster
if [ "$(uname -m)" != "x86_64" ] &&
[ "$(get_os_version buster)" != "0" ] &&
[ -f "tools/config.buster" ]; then
# shellcheck disable=SC1091
source tools/config.buster
return 0
fi
## bullseye
if [ "$(uname -m)" != "x86_64" ] &&
[ "$(get_os_version bullseye)" != "0" ] &&
[ -f "tools/config.bullseye" ]; then
# shellcheck disable=SC1091
source tools/config.bullseye
return 0
fi
## Ubuntu ARM (armv7l) tested on v20.04
# Thanks to https://github.com/gdachs
# To my sadness he didnt make wanted changes in
# https://github.com/mainsail-crew/crowsnest/pull/32
# But I appriciate your work, thx gdachs!
if [ "$(uname -m)" == "armv7l" ] &&
[ "$(get_os_version ubuntu)" != "0" ] &&
[ -f "tools/config.buntu64" ]; then
# shellcheck disable=SC1091
source tools/config.buntu64
return 0
fi
## Ubuntu ARM (aarch64) tested on v22.04
if [ "$(uname -m)" == "aarch64" ] &&
[ "$(get_os_version ubuntu)" != "0" ] &&
[ -f "tools/config.buntu64" ]; then
# shellcheck disable=SC1091
source tools/config.buntu64
return 0
fi
## armbian buster
if [ "$(uname -m)" != "x86_64" ] &&
[ -f "/etc/armbian-release" ] &&
[ "$(get_os_version buster)" != "0" ] &&
[ -f "tools/config.armbian-buster" ]; then
# shellcheck disable=SC1091
source tools/config.armbian-buster
return 0
fi
## armbian bullseye
if [ "$(uname -m)" != "x86_64" ] &&
[ -f "/etc/armbian-release" ] &&
[ "$(get_os_version bullseye)" != "0" ] &&
[ -f "tools/config.armbian-bullseye" ]; then
# shellcheck disable=SC1091
source tools/config.armbian-bullseye
return 0
fi
## armbian jammy
if [ "$(uname -m)" != "x86_64" ] &&
[ -f "/etc/armbian-release" ] &&
[ "$(get_os_version ubuntu)" != "0" ] &&
[ -f "tools/config.buntu64" ]; then
# shellcheck disable=SC1091
source tools/config.buntu64
else
config_msg
return 0
fi
}
create_filestructure() {
for i in "${CROWSNEST_CONFIG_PATH}" "${CROWSNEST_LOG_PATH%/*.*}" "${CROWSNEST_ENV_PATH}"; do
if [[ ! -d "${i}" ]]; then
mkdir -p "${i}"
fi
done
}
### Detect legacy webcamd.
function detect_existing_webcamd {
detect_existing_webcamd() {
local remove
if [ -x "/usr/local/bin/webcamd" ] && [ -d "${HOME}/mjpg-streamer" ]; then
detect_msg
@ -190,7 +136,7 @@ function detect_existing_webcamd {
y|Y|yes|Yes|YES)
echo -en "\nStopping webcamd.service ...\r"
sudo systemctl stop webcamd.service &> /dev/null
echo -e "Stopping webcamd.service ... \t[OK]\r"
echo -e "Stopping webcamd.service ... \t[${CN_OK}]\r"
remove_existing_webcamd
;;
@ -210,163 +156,178 @@ function detect_existing_webcamd {
}
### Remove existing webcamd
function remove_existing_webcamd {
if [ -x "/usr/local/bin/webcamd" ]; then
remove_existing_webcamd() {
if [[ -x "/usr/local/bin/webcamd" ]]; then
echo -en "Removing 'webcamd' ...\r"
sudo rm -f /usr/local/bin/webcamd > /dev/null
echo -e "Removing 'webcamd' ... \t\t[OK]\r"
echo -e "Removing 'webcamd' ... \t\t[${CN_OK}]\r"
fi
if [ -d "${HOME}/mjpg-streamer" ]; then
if [[ -d "${HOME}/mjpg-streamer" ]]; then
echo -en "Removing 'mjpg-streamer' ...\r"
sudo rm -rf "${HOME}"/mjpg-streamer > /dev/null
echo -e "Removing 'mjpg-streamer' ... \t[OK]\r"
echo -e "Removing 'mjpg-streamer' ... \t[${CN_OK}]\r"
fi
if [ -f "/etc/systemd/system/webcamd.service" ]; then
if [[ -f "/etc/systemd/system/webcamd.service" ]]; then
echo -en "Removing 'webcamd.service' ...\r"
sudo systemctl disable webcamd.service &> /dev/null
sudo rm -f /etc/systemd/system/webcamd.service > /dev/null
echo -e "Removing 'webcamd.service' ... \t[OK]\r"
echo -e "Removing 'webcamd.service' ... \t[${CN_OK}]\r"
fi
if [ -f "/var/log/webcamd.log" ]; then
if [[ -f "/var/log/webcamd.log" ]]; then
echo -en "Removing 'webcamd.log' ...\r"
sudo rm -f /var/log/webcamd.log > /dev/null
if [[ -f "${HOME}/klipper_logs/webcamd.log" ]]; then
sudo rm -f "${HOME}"/klipper_logs/webcamd.log > /dev/null
echo -e "Removing 'webcamd.log' ... \t[OK]\r"
fi
if [[ -f "${HOME}/printer_data/logs/webcamd.log" ]]; then
sudo rm -f "${HOME}"/printer_data/logs/webcamd.log > /dev/null
fi
echo -e "Removing 'webcamd.log' ... \t[${CN_OK}]\r"
fi
if [ -f "/etc/logrotate.d/webcamd" ]; then
if [[ -f "/etc/logrotate.d/webcamd" ]]; then
echo -en "Removing 'webcamd' logrotate...\r"
sudo rm -f /etc/logrotate.d/webcamd > /dev/null
echo -e "Removing 'webcamd' logrotate ... \t[OK]\r"
echo -e "Removing 'webcamd' logrotate ... \t[${CN_OK}]\r"
fi
echo -e "\nOld 'webcamd' completly removed."
echo -e "webcam.txt kept,but no longer necessary ..."
}
install_packages() {
### Crowsnest Dependencies
PKGLIST="git crudini bsdutils findutils v4l-utils curl"
### Ustreamer Dependencies
PKGLIST="${PKGLIST} build-essential libevent-dev libjpeg-dev libbsd-dev"
### simple-rtsp-server Dependencies
PKGLIST="${PKGLIST} libxcomposite1 libxtst6 ffmpeg"
echo -e "Running apt update first ..."
### Run apt update
sudo apt-get -q --allow-releaseinfo-change update
function install_crowsnest {
local addconf bin_path logrotatefile moonraker_conf moonraker_update
local crowsnest_bin servicefile template
bin_path="/usr/local/bin"
crowsnest_bin="${HOME}/crowsnest/crowsnest"
template="${PWD}/sample_configs/${CROWSNEST_DEFAULT_CONF}"
servicefile="${PWD}/file_templates/crowsnest.service"
logrotatefile="${HOME}/crowsnest/file_templates/logrotate_crowsnest"
moonraker_conf="${HOME}/klipper_config/moonraker.conf"
moonraker_update="${PWD}/file_templates/moonraker_update.txt"
## helper func moonraker update_manager
function add_update_entry {
if [ -f "${moonraker_conf}" ]; then
# make sure no file exist
if [ -f "/tmp/moonraker.conf" ]; then
sudo rm -f /tmp/moonraker.conf
fi
echo -e "Adding [update_manager] entry ..."
sudo -u "${BASE_USER}" \
cp "${moonraker_conf}" "${moonraker_conf}.backup" &&
cat "${moonraker_conf}" "${moonraker_update}" > /tmp/moonraker.conf &&
cp -rf /tmp/moonraker.conf "${moonraker_conf}"
if [ "${UNATTENDED}" == "true" ]; then
sudo rm -f "${moonraker_conf}.backup"
fi
else
echo -e "moonraker.conf is missing ... [SKIPPED]"
fi
}
echo -e "\nInstall crowsnest Service ..."
## Install Dependencies
echo -e "Installing 'crowsnest' Dependencies ..."
# shellcheck disable=2086
sudo apt install --yes --no-install-recommends ${CROWSNEST_CROWSNEST_DEPS} > /dev/null
echo -e "Installing 'crowsnest' Dependencies ... [OK]"
## Link crowsnest to $PATH
# shellcheck disable=SC2086
# disable because we want 'wordsplitting'
sudo apt-get install -q -y --no-install-recommends ${PKGLIST}
if [[ "$(get_os_version buster)" != "0" ]]; then
sudo apt-get install -q -y --no-install-recommends libraspberrypi-dev
fi
echo -e "Installing 'crowsnest' Dependencies ... [${CN_OK}]"
}
install_crowsnest() {
local bin_path config config_log_path crowsnest_bin
bin_path="/usr/local/bin"
config="${CROWSNEST_CONFIG_PATH}/crowsnest.conf"
crowsnest_bin="/home/${BASE_USER}/crowsnest/crowsnest"
# Link crowsnest to $PATH
echo -en "Linking crowsnest ...\r"
# Remove if exist!
if [[ -f /usr/local/bin/crowsnest ]]; then
rm -f /usr/local/bin/crowsnest
fi
sudo ln -sf "${crowsnest_bin}" "${bin_path}" > /dev/null
echo -e "Linking crowsnest ... [OK]\r"
## Copy crowsnest.conf
# Make sure config directory exists!
if [ ! -d "${CROWSNEST_DEFAULT_CONF_DIR}" ]; then
sudo -u "${BASE_USER}" mkdir -p "${CROWSNEST_DEFAULT_CONF_DIR}"
echo -e "Linking crowsnest ... [${CN_OK}]\r"
# Install base line config
if [[ -f "${config}" ]]; then
echo -e "Found existing 'crowsnest.conf' in ${CROWSNEST_CONFIG_PATH}"
echo -e "Checking log_path ..."
config_log_path="$(crudini --get "${config}" crowsnest log_path)"
# strip out file name (crowsnest.log)
if [[ "${config_log_path%/*.*}" != "${CROWSNEST_LOG_PATH}" ]]; then
echo -e "Setup new log_path: ${CROWSNEST_LOG_PATH}"
sed -i 's|'"${config_log_path}"'|'"${CROWSNEST_LOG_PATH}/crowsnest.log"'|' "${config}"
# Strip full path to tilde
sed -i 's|'"/home/${BASE_USER}"'|~|g' "${config}"
fi
if [[ "${config_log_path%/*.*}" = "${CROWSNEST_LOG_PATH}" ]]; then
echo -e "Entry matching ... [${CN_OK}]"
# Strip full path to tilde
sed -i 's|'"/home/${BASE_USER}"'|~|g' "${config}"
fi
fi
# Make sure not to overwrite existing!
if [ ! -f "${CROWSNEST_DEFAULT_CONF_DIR}/crowsnest.conf" ]; then
# Make sure not overwrite existing!
if [[ ! -f "${config}" ]]; then
echo -en "Copying crowsnest.conf ...\r"
sudo -u "${BASE_USER}" cp -rf "${template}" "${CROWSNEST_DEFAULT_CONF_DIR}"/crowsnest.conf
echo -e "Copying crowsnest.conf ... [OK]\r"
sudo -u "${BASE_USER}" \
cp -f "${CROWSNEST_DEFAULT_CONF}" "${config}" &> /dev/null
sed -i 's|%LOGPATH%|'"${CROWSNEST_LOG_PATH}"'|g' "${config}"
# Strip full path to tilde
sed -i 's|'"/home/${BASE_USER}"'|~|g' "${config}"
echo -e "Copying crowsnest.conf ... [${CN_OK}]\r"
fi
## Copy crowsnest.service
echo -en "Copying crowsnest.service file ...\r"
sudo cp -rf "${servicefile}" /etc/systemd/system/crowsnest.service > /dev/null
if [ ! "${BASE_USER}" == "pi" ]; then
sudo sed -i 's|pi|'"${BASE_USER}"'|g' /etc/systemd/system/crowsnest.service
fi
echo -e "Copying crowsnest.service file ... [OK]\r"
## Copy logrotate
echo -en "Linking logrotate file ...\r"
sudo cp -rf "${logrotatefile}" /etc/logrotate.d/crowsnest
if [ ! "${BASE_USER}" == "pi" ]; then
sudo sed -i 's|pi|'"${BASE_USER}"'|g' /etc/logrotate.d/crowsnest
fi
echo -e "Linking logrotate file ... [OK]\r"
## update systemd if not unattended
if [ "${UNATTENDED}" == "false" ] && [ "$(stat -c %i /)" == "2" ]; then
echo -en "Reload systemd to enable new deamon ...\r"
sudo systemctl daemon-reload
echo -e "Reload systemd to enable new daemon ... [OK]"
fi
## enable crowsnest.service
echo -en "Enable crowsnest.service on boot ...\r"
sudo systemctl enable crowsnest.service &> /dev/null
echo -e "Enable crowsnest.service on boot ... [OK]\r"
## Add moonraker update manager entry
## Unattended
if [ "${UNATTENDED}" == "true" ] &&
[ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" == "1" ] &&
[ -f "${moonraker_conf}" ]; then
echo -en "Adding Crowsnest Update Manager entry to moonraker.conf ...\r"
add_update_entry
echo -e "Adding Crowsnest Update Manager entry to moonraker.conf ... [OK]"
fi
## Manual install
if [ "${UNATTENDED}" != "true" ] &&
[ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" != "0" ]; then
while true; do
read -erp "Do you want to add [update_manager] entry? (y/N) " -i "N" addconf
case "${addconf}" in
y|Y|yes|Yes|YES)
if [ "$(grep -c "crowsnest" "${moonraker_conf}")" == "0" ]; then
add_update_entry
else
echo -e "Update Manager entry already exists moonraker.conf ... [SKIPPED]"
fi
break
;;
return 0
}
n|N|no|No|NO)
echo -e "Adding Crowsnest Update Manager entry to moonraker.conf ... [SKIPPED]"
break
;;
install_service_file() {
local servicefile systemd_dir
servicefile="${PWD}/resources/crowsnest.service"
systemd_dir="/etc/systemd/system"
echo -en "Install crowsnest.service file ...\r"
# Install Service file
cp -f "${servicefile}" "${systemd_dir}"
sed -i 's|%USER%|'"${BASE_USER}"'|g;s|%ENV%|'"${CROWSNEST_ENV_PATH}/crowsnest.env"'|g' \
"${systemd_dir}/crowsnest.service"
# create and install env file
echo -e "CROWSNEST_ARGS=\"-c ${CROWSNEST_CONFIG_PATH}/crowsnest.conf\"\n" > "${CROWSNEST_ENV_PATH}/crowsnest.env"
chown -f "${BASE_USER}":"${BASE_USER}" "${CROWSNEST_ENV_PATH}/crowsnest.env"
echo -e "Install crowsnest.service file ... [${CN_OK}]\r"
}
*)
echo -e "\nInvalid input, please try again."
;;
esac
done
fi
install_logrotate() {
local logrotatefile logpath
logrotatefile="resources/logrotate_crowsnest"
logpath="${CROWSNEST_LOG_PATH}/crowsnest.log"
# install logrotate
echo -en "Install logrotate file ...\r"
cp -rf "${logrotatefile}" /etc/logrotate.d/crowsnest
sed -i 's|%LOGPATH%|'"${logpath}"'|g' /etc/logrotate.d/crowsnest
echo -e "Install logrotate file ... [${CN_OK}]\r"
}
## add $USER to group video
echo -en "Add User ${BASE_USER} to group 'video' ...\r"
if [ "$(groups | grep -c video)" == "0" ]; then
sudo usermod -aG video "${BASE_USER}" > /dev/null
echo -e "Add User ${BASE_USER} to group 'video' ... [OK]"
add_update_entry() {
local moonraker_conf
moonraker_conf="${CROWSNEST_CONFIG_PATH}/moonraker.conf"
moonraker_update="${PWD}/resources/moonraker_update.txt"
echo -en "Adding Crowsnest Update Manager entry to moonraker.conf ...\r"
if [[ -f "${moonraker_conf}" ]]; then
if [[ "$(grep -c "crowsnest" "${moonraker_conf}")" != "0" ]]; then
echo -e "Update Manager entry already exists moonraker.conf ... [${CN_SK}]"
return 0
fi
# make sure no file exist
if [[ -f "/tmp/moonraker.conf" ]]; then
sudo rm -f /tmp/moonraker.conf
fi
sudo -u "${BASE_USER}" \
cp "${moonraker_conf}" "${moonraker_conf}.backup" &&
cat "${moonraker_conf}" "${moonraker_update}" > /tmp/moonraker.conf &&
cp -rf /tmp/moonraker.conf "${moonraker_conf}"
if [[ "${CROWSNEST_UNATTENDED}" = "1" ]]; then
sudo rm -f "${moonraker_conf}.backup"
fi
echo -e "Adding Crowsnest Update Manager entry to moonraker.conf ... [${CN_OK}]"
else
echo -e "Add User ${BASE_USER} to group 'video' ... [SKIPPED]"
echo -e "moonraker.conf is missing ... [${CN_SK}]"
fi
}
## add $USER to group video
add_group_video() {
echo -en "Add User ${BASE_USER} to group 'video' ...\r"
if [[ "$(groups "${BASE_USER}" | grep -c video)" == "0" ]]; then
usermod -aG video "${BASE_USER}" > /dev/null
echo -e "Add User ${BASE_USER} to group 'video' ... [${CN_OK}]"
else
echo -e "Add User ${BASE_USER} to group 'video' ... [${CN_SK}]"
echo -e "==> User ${BASE_USER} is already in group 'video'"
fi
}
function clone_ustreamer {
clone_ustreamer() {
## remove bin/ustreamer if exist
if [ -d bin/ustreamer ]; then
if [[ -d bin/ustreamer ]]; then
rm -rf bin/ustreamer
fi
git clone "${CROWSNEST_USTREAMER_REPO_SHIP}" \
@ -374,85 +335,188 @@ function clone_ustreamer {
## Buster workaround
## ustreamer support omx only till version 4.13
## so stick to that version
if [ "$(get_os_version buster)" != "0" ]; then
if [[ "$(get_os_version buster)" != "0" ]]; then
pushd bin/ustreamer &> /dev/null || exit 1
git reset --hard 61ab2a8
popd &> /dev/null || exit 1
fi
}
function build_apps {
build_apps() {
echo -e "Build dependend Stream Apps ..."
echo -e "Cloning ustreamer repository ..."
clone_ustreamer
echo -e "Installing 'ustreamer' Dependencies ..."
# shellcheck disable=2086
sudo apt install --yes --no-install-recommends ${CROWSNEST_USTREAMER_DEPS} > /dev/null
echo -e "Installing 'ustreamer' Dependencies ... [OK]"
pushd bin > /dev/null
make all
popd > /dev/null
}
function install_raspicam_fix {
if [ -f /proc/device-tree/model ] &&
grep -q "Raspberry" /proc/device-tree/model ; then
echo -en "Applying Raspicam Fix ... \r"
sudo sh -c 'echo "bcm2835-v4l2" >> /etc/modules'
sudo cp file_templates/bcm2835-v4l2.conf /etc/modprobe.d/
echo -e "Applying Raspicam Fix ... [OK]"
is_raspberry_pi() {
if [[ -f /proc/device-tree/model ]] &&
grep -q "Raspberry" /proc/device-tree/model; then
echo "1"
else
echo -e "This is not a Raspberry Pi!"
echo -e "Applying Raspicam Fix ... [SKIPPED]"
echo "0"
fi
}
function enable_legacy_cam {
install_raspicam_fix() {
if [[ "${CROWSNEST_RASPICAMFIX}" == "auto" ]]; then
if [[ "$(is_raspberry_pi)" = "1" ]]; then
echo -e "Device is a Raspberry Pi"
CROWSNEST_RASPICAMFIX="1"
fi
if [[ "$(is_raspberry_pi)" = "0" ]]; then
echo -e "Device is \e[31mNOT\e[0m a Raspberry Pi ... [${CN_SK}]"
CROWSNEST_RASPICAMFIX="0"
fi
fi
if [[ "${CROWSNEST_RASPICAMFIX}" == "1" ]]; then
echo -en "Applying Raspicam Fix ... \r"
bash -c 'echo "bcm2835-v4l2" >> /etc/modules'
cp resources/bcm2835-v4l2.conf /etc/modprobe.d/
echo -e "Applying Raspicam Fix ... [${CN_OK}]"
fi
}
enable_legacy_cam() {
local cfg
local -a model
cfg="/boot/config.txt"
echo -en "Enable legacy camera stack ... \r"
sudo sed -i "s/camera_auto_detect=1/#camera_auto_detect=1/" "${cfg}"
if [ "$(grep -c "start_x" "${cfg}")" == "0" ]; then
sudo crudini --set --inplace "${cfg}" all start_x 1 &> /dev/null
model=(pi3 pi4)
if [[ -f "${cfg}" ]] && [[ "$(is_raspberry_pi)" = "1" ]]; then
# Helper func
get_val() {
crudini --get "${cfg}" "${1}" gpu_mem 2> /dev/null
}
echo -en "Enable legacy camera stack ... \r"
sed -i "s/camera_auto_detect=1/#camera_auto_detect=1/" "${cfg}"
if [[ "$(grep -c "start_x" "${cfg}")" = "0" ]]; then
crudini --set --inplace "${cfg}" all start_x 1 &> /dev/null
fi
for d in "${model[@]}"; do
if [[ "$(get_val "${d}")" -lt "129" ]]; then
crudini --set --inplace "${cfg}" "${d}" gpu_mem 256 &> /dev/null
fi
done
if [[ "$(get_val pi0)" -lt "129" ]]; then
sudo crudini --set --inplace "${cfg}" pi0 gpu_mem 160 &> /dev/null
fi
echo -e "Enable legacy camera stack ... [${CN_OK}]"
fi
if [ "$(grep -c "gpu_mem" "${cfg}")" == "0" ]; then
sudo crudini --set --inplace "${cfg}" pi4 gpu_mem 256 &> /dev/null
sudo crudini --set --inplace "${cfg}" all gpu_mem 128 &> /dev/null
fi
echo -e "Enable legacy camera stack ... [OK]"
}
#### MAIN
while getopts "z" arg; do
case ${arg} in
z)
echo "WARN: Running in UNATTENDED Mode ..."
set -x
UNATTENDED="true"
;;
*)
UNATTENDED="false"
;;
esac
done
install_cleanup_trap
import_config
welcome_msg
if [ "${UNATTENDED}" != "true" ]; then
detect_existing_webcamd
fi
echo -e "Running apt update first ..."
sudo apt update
install_crowsnest
build_apps
if [ "${UNATTENDED}" != "true" ] &&
[ "${CROWSNEST_FORCE_RASPICAMFIX}" != "0" ]; then
install_raspicam_fix
fi
if [ "$(get_os_version bullseye)" != "0" ] &&
[ -f "/boot/config.txt" ]; then
enable_legacy_cam
fi
goodbye_msg
## enable service
enable_service() {
echo -en "Enable crowsnest.service on boot ...\r"
sudo systemctl enable crowsnest.service &> /dev/null
echo -e "Enable crowsnest.service on boot ... [${CN_OK}]\r"
}
## start systemd service
start_service() {
sudo systemctl daemon-reload &> /dev/null
sudo systemctl start crowsnest.service &> /dev/null
}
## ask reboot
ask_reboot() {
local reply
while true; do
read -erp "Reboot NOW? [y/N]: " -i "N" reply
case "${reply}" in
[yY]*)
echo -e "Going to reboot in 5 seconds!"
sleep 5
reboot
;;
[nN]*)
echo -e "\n\e[31mNot to reboot may cause issues!"
echo -e "Reboot as soon as possible!\e[0m\n"
echo -e "Goodbye ..."
break
;;
* )
echo -e "\e[31mERROR:\e[0m Please choose Y or N !"
;;
esac
done
}
## Main func
main() {
## Initialize traps
install_cleanup_trap
## Welcome message
welcome_msg
## Step 1: import .config file
if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then
import_config
fi
## Make sure folders exist
create_filestructure
## Step 2: Detect existing webcamd
if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then
detect_existing_webcamd
fi
## Step 3: Install dependencies
install_packages
## Step 4: Install crowsnest
install_crowsnest
## Step 5: Build Applications
build_apps
## Step 6: Add $USER to group 'video'
add_group_video
## Step 7: Enable Legacy Camera Stack
if [[ "$(get_os_version bullseye)" != "0" ]] &&
[[ -f "/boot/config.txt" ]]; then
enable_legacy_cam
fi
## Step 8: Install service File
install_service_file
## Step 9: Enable service
## If unattended skip enable and start service
if [[ -f /etc/systemd/system/crowsnest.service ]] &&
[[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then
enable_service
fi
if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then
start_service
fi
## Step 10: Install logrotate file
install_logrotate
## Step 11: Install raspicamfix
install_raspicam_fix
## Step 12: Add moonraker update_manager entry
if [[ "${CROWSNEST_UNATTENDED}" = "1" ]] ||
[[ "${CROWSNEST_ADD_CROWSNEST_MOONRAKER}" = "1" ]]; then
add_update_entry
fi
## Step 13: Ask for reboot
## Skip if UNATTENDED
goodbye_msg
if [[ "${CROWSNEST_UNATTENDED}" = "0" ]]; then
ask_reboot
fi
}
main
exit 0

View File

@ -2,7 +2,7 @@
#### crowsnest - A webcam Service for multiple Cams and Stream Services.
####
#### Written by Stephan Wendel aka KwadFan <me@stephanwe.de>
#### Copyright 2021
#### Copyright 2021 - 2022
#### https://github.com/mainsail-crew/crowsnest
####
#### This File is distributed under GPLv3
@ -17,21 +17,36 @@ set -Ee
# set -x
# Global Vars
TITLE="crowsnest - A Webcam Daemon for Raspberry Pi OS"
TITLE="\e[31mcrowsnest\e[0m - A webcam daemon for multiple Cams and stream services."
CN_CONFIG_ENVPATH="$(find "${HOME}" -name "crowsnest.env")"
# Message Vars
CN_OK="\e[32mOK\e[0m"
CN_SK="\e[33mSKIPPED\e[0m"
### Check non-root
if [[ ${UID} = '0' ]]; then
echo -e "\n\tYOU DONT NEED TO RUN UNINSTALLER AS ROOT!"
echo -e "\tYou will be prompted for 'sudo' passwd"
exit 1
fi
### Functions
### Messages
### Welcome Message
function welcome_msg {
welcome_msg() {
echo -e "${TITLE}\n"
echo -e "\tSome Parts of the Uninstaller requires 'root' privileges."
echo -e "\tYou will be prompted for your 'sudo' password, if needed.\n"
echo -e "\t\e[34mAhoi!\e[0m"
echo -e "\tTo sad that you want to uninstall crowsnest :("
echo -e "\tThis will take a while ... "
echo -e "\tPlease reboot after installation has finished.\n"
sleep 1
}
function goodbye_msg {
echo -e "Please remove manually the 'crowsnest' folder in ${HOME}"
echo -e "Remove [update manager crowsnest] section from moonraker.conf!"
goodbye_msg() {
echo -e "Please remove manually the 'crowsnest' folder in ${HOME}\n"
echo -e "\tRemove [update manager crowsnest] section from moonraker.conf,before reboot!\n"
echo -e "After that is done, please reboot!\nGoodBye...\n"
}
@ -40,12 +55,12 @@ function goodbye_msg {
## Credits to guysoft!
## https://github.com/guysoft/CustomPiOS
function install_cleanup_trap() {
install_cleanup_trap() {
# kills all child processes of the current process on SIGINT or SIGTERM
trap 'cleanup' SIGINT SIGTERM
}
function cleanup() {
cleanup() {
# make sure that all child processed die when we die
echo -e "Killed by user ...\r\nGoodBye ...\r"
# shellcheck disable=2046
@ -53,7 +68,7 @@ function cleanup() {
}
##
function err_exit {
err_exit() {
if [ "${1}" != "0" ]; then
echo -e "ERROR: Error ${1} occured on line ${2}"
echo -e "ERROR: Stopping $(basename "$0")."
@ -69,16 +84,18 @@ trap 'err_exit $? $LINENO' ERR
### Uninstall crowsnest
function ask_uninstall {
ask_uninstall() {
local remove
if [ -x "/usr/local/bin/crowsnest" ] && [ -d "${HOME}/crowsnest" ]; then
while true; do
read -erp "Do you REALLY want to remove existing 'crowsnest'? (y/N) " -i "N" remove
case "${remove}" in
y|Y|yes|Yes|YES)
source_env_file
uninstall_crowsnest
remove_raspicam_fix
remove_logrotate
ask_remove_config
goodbye_msg
break
;;
@ -98,44 +115,81 @@ function ask_uninstall {
fi
}
function uninstall_crowsnest {
source_env_file() {
# shellcheck disable=SC1090
. "${CN_CONFIG_ENVPATH}"
}
uninstall_crowsnest() {
local servicefile bin_path
servicefile="/etc/systemd/system/crowsnest.service"
bin_path="/usr/local/bin/crowsnest"
# Dirty hack to grant sudo priviledges
# and not overwriting next \r line
sudo sh -c 'echo "" > /dev/null'
echo -en "\nStopping crowsnest.service ...\r"
sudo systemctl stop crowsnest.service &> /dev/null
echo -e "Stopping crowsnest.service ... \t[OK]\r"
echo -e "Stopping crowsnest.service ... \t[${CN_OK}]\r"
echo -en "\nDisable crowsnest.service ...\r"
sudo systemctl disable crowsnest.service &> /dev/null
echo -e "Disable crowsnest.service ... \t[OK]\r"
echo -e "Disable crowsnest.service ... \t[${CN_OK}]\r"
echo -en "Uninstalling crowsnest.service...\r"
if [ -f "${servicefile}" ]; then
if [[ -f "${servicefile}" ]]; then
sudo rm -f "${servicefile}"
fi
if [ -x "${bin_path}" ]; then
if [[ -x "${bin_path}" ]]; then
sudo rm -f "${bin_path}"
fi
echo -e "Uninstalling crowsnest.service...[OK]\r"
echo -e "Uninstalling crowsnest.service...[${CN_OK}]\r"
if [[ -n "${CN_CONFIG_ENVPATH}" ]]; then
echo -en "Removing crowsnest.env ...\r"
sudo rm -f "${CN_CONFIG_ENVPATH}"
echo -e "Removing crowsnest.env ... [${CN_OK}]\r"
fi
}
function remove_raspicam_fix {
if [ -f /etc/modprobe.d/bcm2835-v4l2.conf ] &&
[ -f /proc/device-tree/model ] &&
ask_remove_config() {
local config reply
config="${CROWSNEST_ARGS/-c /}"
while true; do
read -erp "Do you want to remove crowsnest.conf? [y/N]: " -i "N" reply
case "${reply}" in
[yY]* )
sudo rm -f "${config}"
echo -e "Removing 'crowsnest.conf' ... [${CN_OK}]\r"
break
;;
[nN]* )
echo -e "Removing 'crowsnest.conf' ... [${CN_SK}]\r"
break
;;
* )
echo -e "\e[31mERROR: Not a valid choice, try again ...\e[0m"
;;
esac
done
return 0
}
remove_raspicam_fix() {
if [[ -f /etc/modprobe.d/bcm2835-v4l2.conf ]] &&
[[ -f /proc/device-tree/model ]] &&
grep -q "Raspberry" /proc/device-tree/model ; then
echo -en "Removing Raspicam Fix ...\r"
sudo sed -i '/bcm2835/d' /etc/modules
sudo rm -f /etc/modprobe.d/bcm2835-v4l2.conf
echo -e "Removing Raspicam Fix ... [OK]"
echo -e "Removing Raspicam Fix ... [${CN_OK}]"
else
echo -e "This is not a Raspberry Pi!"
echo -e "Removing Raspicam Fix ... [SKIPPED]"
echo -e "Removing Raspicam Fix ... [${CN_SK}]"
echo -e "\tThis is not a Raspberry Pi"
echo -e "\tor Raspicamfix not installed ... \n"
fi
}
function remove_logrotate {
echo -en "Removing Logrotate Rule ...\r"
sudo rm -f /etc/logrotate.d/crowsnest
echo -e "Removing Logrotate Rule ... [OK]"
echo -e "Removing Logrotate Rule ... [${CN_OK}]"
}
#### MAIN