diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..4ff871410 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# Funding +patreon: meteyou +ko_fi: mainsail diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..c7032b913 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,42 @@ +name: Bug report +description: Create a report to help us improve +labels: ["bug", "triage"] +body: + - type: markdown + attributes: + value: | + This issue form is for reporting bugs only! + If you have a feature request, please use [feature_request](/new?template=feature_request.yml) + - type: textarea + id: what-happened + attributes: + label: What happened + description: >- + A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: What did you expect to happen + description: >- + A clear and concise description of what you expected to happen. + validations: + required: true + - type: textarea + id: repro-steps + attributes: + label: How to reproduce + description: >- + Minimal and precise steps to reproduce this bug. + validations: + required: true + - type: textarea + id: additional-info + attributes: + label: Additional information + description: | + If you have any additional information for us, use the field below. + + Please note, you can attach logs, screenshots or screen recordings here, by + dragging and dropping files in the field below. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..d75ce0ea9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Mainsail Discord + url: https://discord.gg/skWTwTD + about: Quickest way to get in contact diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..19e3a4e87 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,40 @@ +name: Feature request +description: Suggest an idea for this project +labels: ["feature request"] +body: + - type: markdown + attributes: + value: | + This issue form is for feature requests only! + If you've found a bug, please use [bug_report](/new?template=bug_report.yml) + - type: textarea + id: problem-description + attributes: + label: Is your feature request related to a problem? Please describe + description: >- + A clear and concise description of what the problem is. + validations: + required: true + - type: textarea + id: solution-description + attributes: + label: Describe the solution you'd like + description: >- + A clear and concise description of what you want to happen. + validations: + required: true + - type: textarea + id: possible-alternatives + attributes: + label: Describe alternatives you've considered + description: >- + A clear and concise description of any alternative solutions or features you've considered. + - type: textarea + id: additional-info + attributes: + label: Additional information + description: | + If you have any additional information for us, use the field below. + + Please note, you can attach logs, screenshots or screen recordings here, by + dragging and dropping files in the field below. diff --git a/.github/sdcard-logo.png b/.github/sdcard-logo.png new file mode 100644 index 000000000..0934c25d2 Binary files /dev/null and b/.github/sdcard-logo.png differ diff --git a/README.md b/README.md index 218593511..bedcb0b83 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,32 @@ ![downloads](https://img.shields.io/github/downloads/mainsail-crew/MainsailOS/total) -[![discord](https://img.shields.io/discord/758059413700345988?color=%235865F2&label=discord&logo=discord&logoColor=white&style=flat)](https://discord.gg/skWTwTD) +[![discord](https://img.shields.io/discord/758059413700345988?color=%235865F2&label=discord&logo=discord&logoColor=white&style=flat)](https://discord.gg/mainsail) + +

+ +

# MainsailOS -![Mainsail Logo](https://github.com/meteyou/mainsail/raw/master/docs/assets/img/logo.png?raw=true) +A [Raspberry Pi OS](https://www.raspberrypi.org/software/) based distribution for 3D Printers. \ +It includes everything to get started with Klipper Firmware and Mainsail. + +Learn more about: -A [Raspberry Pi OS](https://www.raspberrypi.org/software/) based distribution for 3d Printers. It includes everything to get started with Klipper Firmware and Mainsail. +- [Klipper Firmware](https://www.klipper3d.org/) +- [Moonraker](https://moonraker.readthedocs.io/en/latest/) +- [Mainsail](https://docs.mainsail.xyz/) -Learn More about... -Klipper Firmware: https://www.klipper3d.org/ -Moonraker: https://moonraker.readthedocs.io/en/latest/ -Mainsail: https://docs.mainsail.xyz/ +## How to install MainsailOS ? -## Installing +You can find detailed instructions in our [documentation](https://docs.mainsail.xyz/setup/mainsail-os). -See the installation instructions on the Mainsail documentation page: -https://docs.mainsail.xyz/setup/mainsail-os +We recommend the installation via [Raspberry Pi Imager](https://docs.mainsail.xyz/setup/mainsailos/pi-imager). ## Community -For additional help, join us in the [Mainsail Discord](https://discord.gg/skWTwTD). +For additional help, join us on [Discord](https://discord.gg/mainsail). -[![discord](https://img.shields.io/discord/758059413700345988?color=%235865F2&label=discord&logo=discord&logoColor=white&style=flat)](https://discord.gg/skWTwTD) +[![discord](https://img.shields.io/discord/758059413700345988?color=%235865F2&label=discord&logo=discord&logoColor=white&style=flat)](https://discord.gg/mainsail) ## What is included? @@ -30,30 +35,30 @@ Here a list of included and preinstalled Software: - [Klipper (3D Printer Firmware)](https://github.com/KevinOConnor/klipper) - [Moonraker (API Web Server for Klipper)](https://github.com/Arksine/moonraker) - [Mainsail (Web interface for Klipper/Moonraker)](https://github.com/meteyou/mainsail) -- [Mjpeg-streamer (Webcam streaming)](https://github.com/jacksonliam/mjpg-streamer) +- [Crowsnest (Webcam streaming)](https://github.com/mainsail-crew/crowsnest) +- [Sonar (Keepalive daemon)](https://github.com/mainsail-crew/sonar) - [Nginx (Webserver & Proxy)](https://nginx.org/en/) -- [FFMPEG (upcoming features)](https://www.ffmpeg.org/) + +## also includes + +- Enabled Serial Connection by default. \ + Using Hardware UART (PL011) for Boards like BTT SKR Mini E3 V3 +- Preinstalled Dependencies for Klipper's Input Shaper. \ + You only need to build the [klipper_mcu](https://www.klipper3d.org/RPi_microcontroller.html) and installing the service. \ + See [Klipper documentation](https://www.klipper3d.org/Measuring_Resonances.html) for more information. +- Preinstalled python3-serial package, needed for [CanBoot](https://github.com/Arksine/CanBoot) ## Screenshots -![screenshot-dashboard](https://raw.githubusercontent.com/mainsail-crew/docs/master/assets/img/screenshot.png) +![screenshot-dashboard](https://github.com/mainsail-crew/docs/raw/master/assets/img/screenshot.png) # Build your own / Developing To prevent you have to deal with an entire build chain setup, \ simply fork this repository. -Enable the workflows in your fork and you are good to go. -On every push you make, it will build an Image and upload it as artifact. - -If you want or need to build locally please visit [CustomPiOS](https://github.com/guysoft/CustomPiOS) -Especcially ["Build a Distro From within Raspbian / Debian / Ubuntu / CustomPiOS Distros"](https://github.com/guysoft/CustomPiOS#build-a-distro-from-within-raspbian--debian--ubuntu--custompios-distros) - ---- - -## Credits +Enable the workflows in your fork and you are good to go. \ +On each push you make, an image is build and uploaded as an artifact. -We want to give a shoutout to [jottr](https://github.com/jottr) for mentioning a naming convention problem.\ -In the past we used 'raspbian' at some points for names.\ -But this isn't technicaly true.\ -MainsailOS is based of Raspberry Pi OS, not raspbian. +If you want or need to build locally please visit [CustomPiOS](https://github.com/guysoft/CustomPiOS). \ +Especially ["Build a Distro From within Raspbian / Debian / Ubuntu / CustomPiOS Distros"](https://github.com/guysoft/CustomPiOS#build-a-distro-from-within-raspbian--debian--ubuntu--custompios-distros) diff --git a/src/config b/src/config index 47c414659..ea9e7bc4b 100644 --- a/src/config +++ b/src/config @@ -2,8 +2,8 @@ # Shebang for better detection of file type export DIST_NAME=MainsailOS -export DIST_VERSION=0.6.1 +export DIST_VERSION=0.7.0 export BASE_IMAGE_ENLARGEROOT=2500 -export MODULES="base,pkgupgrade,mainsailos(network,piconfig,klipper,is_req_preinstall,moonraker,mainsail,mjpgstreamer,serialcomm,password-for-sudo)" +export MODULES="base,pkgupgrade,mainsailos(network,piconfig,klipper,is_req_preinstall,moonraker,timelapse,mainsail,crowsnest,sonar,password-for-sudo),postrename" export BASE_RELEASE_COMPRESS=yes export BASE_IMAGE_RESIZEROOT=600 diff --git a/src/modules/crowsnest/config b/src/modules/crowsnest/config new file mode 100644 index 000000000..d12c02d7e --- /dev/null +++ b/src/modules/crowsnest/config @@ -0,0 +1,28 @@ +#!/bin/bash +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 +#### 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 + + +# 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" diff --git a/src/modules/crowsnest/start_chroot_script b/src/modules/crowsnest/start_chroot_script new file mode 100644 index 000000000..9f75b2c6d --- /dev/null +++ b/src/modules/crowsnest/start_chroot_script @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +#### crowsnest - A webcam Service for multiple Cams and Stream Services. +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 +#### https://github.com/mainsail-crew/crowsnest +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck disable=all + +# Error handling +set -Ee + +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 +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 +popd &> /dev/null || exit 1 diff --git a/src/modules/is_req_preinstall/config b/src/modules/is_req_preinstall/config index 8c44ef35d..ab8e7aa6e 100644 --- a/src/modules/is_req_preinstall/config +++ b/src/modules/is_req_preinstall/config @@ -1,4 +1,6 @@ +#!/bin/bash +# shellcheck disable=all [ -n "$IS_REQ_PREINSTALL_VENV_DIR" ] || IS_REQ_PREINSTALL_VENV_DIR=/home/${BASE_USER}/klippy-env [ -n "$IS_REQ_PREINSTALL_DEPS" ] || IS_REQ_PREINSTALL_DEPS="python3-numpy python3-matplotlib" -[ -n "$IS_REQ_PREINSTALL_PIP" ] || IS_REQ_PREINSTALL_PIP="numpy" -[ -n "$IS_REQ_PREINSTALL_CFG_FILE" ] || IS_REQ_PREINSTALL_CFG_FILE="/boot/config.txt" \ No newline at end of file +[ -n "$IS_REQ_PREINSTALL_PIP" ] || IS_REQ_PREINSTALL_PIP="numpy<=1.21.4" +[ -n "$IS_REQ_PREINSTALL_CFG_FILE" ] || IS_REQ_PREINSTALL_CFG_FILE="/boot/config.txt" diff --git a/src/modules/is_req_preinstall/start_chroot_script b/src/modules/is_req_preinstall/start_chroot_script index a5a6effc9..fde8d9285 100644 --- a/src/modules/is_req_preinstall/start_chroot_script +++ b/src/modules/is_req_preinstall/start_chroot_script @@ -1,59 +1,61 @@ #!/usr/bin/env bash -# -# Copyright 2021 by Stephan Wendel aka KwadFan -# -# This file may distributed under GPLv3 -######## - -### For easier maintainability look to klipper/config. +#### MainsailOS Build Chain +#### +#### Klipper Install Module +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 - 2022 +#### https://github.com/mainsail-crew/MainsailOS +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces ## Source error handling, leave this in place -set -xe +set -Eex + +# Set LC_ALL to prevent errors +export LC_ALL=C + +# Set DEBIAN_FRONTEND to noninteractive +if [ "${DEBIAN_FRONTEND}" != "noninteractive" ]; then + export DEBIAN_FRONTEND=noninteractive +fi # Source CustomPIOS common.sh +# shellcheck disable=SC1091 source /common.sh install_cleanup_trap -echo_green "Input Shaper Requirements preinstall" +echo_green "Install Input Shaper requirements ..." ### install all deps at once for time consumption reasons. ## APT: Update Repo Database and install Dependencies - +# Force apt update +apt update echo_green "Installing Input Shaper Dependencies ..." -apt update && apt install ${IS_REQ_PREINSTALL_DEPS} -y - -### numpy Parallelizing -function max_cores() { - local core_count - core_count="$(nproc)" - if [ "${core_count}" -lt 3 ]; then - echo "$core_count" - else - echo "$(("${core_count}" -1))" - fi -} - -echo_green "System has $(nproc) Cores available." -echo_green "Using $(max_cores)..." -export NPY_NUM_BUILD_JOBS="$(max_cores)" - +# shellcheck disable=SC2086 +# Disabling shellcheck SC2086, because we want "wordsplitting" +check_install_pkgs ${IS_REQ_PREINSTALL_DEPS} ### Check for Klipper Venv installed. -pushd /home/${BASE_USER} +pushd "/home/${BASE_USER}" &> /dev/null || exit 1 if [ -d "${IS_REQ_PREINSTALL_VENV_DIR}" ] && [ -x "${IS_REQ_PREINSTALL_VENV_DIR}/bin/pip" ]; then echo_green "Installing numpy..." - sudo -u ${BASE_USER} ${IS_REQ_PREINSTALL_VENV_DIR}/bin/pip install -v "${IS_REQ_PREINSTALL_PIP}" + sudo -u "${BASE_USER}" "${IS_REQ_PREINSTALL_VENV_DIR}"/bin/pip install -v "${IS_REQ_PREINSTALL_PIP}" else echo_red "Klipper Venv not found!" return 1 fi ## Cleanup -sudo -u ${BASE_USER} rm -rf /home/${BASE_USER}/.cache -popd +echo_green "Cleanup ..." +sudo -u "${BASE_USER}" rm -rf "/home/${BASE_USER}/.cache" +popd &> /dev/null || exit 1 ## Enable spi interface by default echo_green "Enabling SPI Interface..." -sed -i 's/#dtparam=spi=on/dtparam=spi=on/' ${IS_REQ_PREINSTALL_CFG_FILE} +sed -i 's/#dtparam=spi=on/dtparam=spi=on/' "${IS_REQ_PREINSTALL_CFG_FILE}" -### EOF \ No newline at end of file +echo_green "Install Input Shaper requirements ... done!" diff --git a/src/modules/klipper/config b/src/modules/klipper/config index 2df7b914c..b4e3b072d 100644 --- a/src/modules/klipper/config +++ b/src/modules/klipper/config @@ -1,10 +1,12 @@ +#!/bin/bash +# shellcheck disable=all [ -n "$KLIPPER_SRC_DIR" ] || KLIPPER_SRC_DIR=/home/${BASE_USER}/klipper [ -n "$KLIPPER_PYTHON_DIR" ] || KLIPPER_PYTHON_DIR=/home/${BASE_USER}/klippy-env [ -n "$KLIPPER_REPO_SHIP" ] || KLIPPER_REPO_SHIP=https://github.com/Klipper3d/klipper.git [ -n "$KLIPPER_REPO_BRANCH" ] || KLIPPER_REPO_BRANCH=master [ -n "$KLIPPER_DEPS" ] || KLIPPER_DEPS="wget git gpiod \ -virtualenv python-dev python-matplotlib \ +virtualenv python3-dev python3-matplotlib \ libffi-dev build-essential \ libncurses-dev libusb-dev \ avrdude gcc-avr binutils-avr avr-libc \ @@ -12,4 +14,4 @@ stm32flash dfu-util libnewlib-arm-none-eabi \ gcc-arm-none-eabi binutils-arm-none-eabi libusb-1.0" [ -n "$KLIPPER_USER_GROUPS" ] || KLIPPER_USER_GROUPS=tty,dialout [ -n "$KLIPPER_USER_DIRS" ] || KLIPPER_USER_DIRS="klipper_config klipper_logs gcode_files" -[ -n "$KLIPPER_PYENV_REQ" ] || KLIPPER_PYENV_REQ=scripts/klippy-requirements.txt \ No newline at end of file +[ -n "$KLIPPER_PYENV_REQ" ] || KLIPPER_PYENV_REQ=scripts/klippy-requirements.txt diff --git a/src/modules/klipper/filesystem/root/etc/systemd/system/klipper.service b/src/modules/klipper/filesystem/root/etc/systemd/system/klipper.service index 5591a27c0..d8dec38ba 100644 --- a/src/modules/klipper/filesystem/root/etc/systemd/system/klipper.service +++ b/src/modules/klipper/filesystem/root/etc/systemd/system/klipper.service @@ -3,7 +3,7 @@ [Unit] Description=Starts Klipper and provides klippy Unix Domain Socket API Documentation=https://www.klipper3d.org/ -After=network.target +After=network-online.target Before=moonraker.service Wants=udev.target @@ -21,4 +21,4 @@ User=pi RemainAfterExit=yes ExecStart= /home/pi/klippy-env/bin/python /home/pi/klipper/klippy/klippy.py ${KLIPPER_CONFIG} -l ${KLIPPER_LOG} -a ${KLIPPER_SOCKET} Restart=always -RestartSec=10 \ No newline at end of file +RestartSec=10 diff --git a/src/modules/klipper/start_chroot_script b/src/modules/klipper/start_chroot_script index af4d408d8..02cfeae12 100644 --- a/src/modules/klipper/start_chroot_script +++ b/src/modules/klipper/start_chroot_script @@ -1,60 +1,83 @@ #!/usr/bin/env bash -# Klipper install script -# Script that installs Klipper -# Written by Raymond Himle and Stefan Dej -# Revamped by KwadFan -# Thanks to KevinOConnor -# GPL V3 -######## +#### MainsailOS Build Chain +#### +#### Klipper Install Module +#### +#### Based on work done by Raymond Himle and Stefan Dej +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2022 +#### https://github.com/mainsail-crew/MainsailOS +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces ### For easier maintainability look to klipper/config. ## Source error handling, leave this in place -set -xe +set -Eex + +## Set LC_ALL to prevent errors +export LC_ALL=C + +# Set DEBIAN_FRONTEND to noninteractive +if [ "${DEBIAN_FRONTEND}" != "noninteractive" ]; then + export DEBIAN_FRONTEND=noninteractive +fi -# Source CustomPIOS common.sh +## Source CustomPIOS common.sh +# shellcheck disable=SC1091 source /common.sh install_cleanup_trap unpack /filesystem/root / -echo_green "Installing Klipper and enable klippy Service" +echo_green "Installing Klipper and enable klippy Service ..." -### install all deps at once for time consumption reasons. +## Install all deps at once for time consumption reasons. ## APT: Update Repo Database and install Dependencies +# Force apt update +apt update +echo_green "Installing Klipper Dependencies ..." +## Disabling shellcheck SC2086, because we want "wordsplitting" +# shellcheck disable=SC2086 +check_install_pkgs ${KLIPPER_DEPS} -apt update && apt install ${KLIPPER_DEPS} -y - -### Make sure user pi has access to serial ports +## Make sure user pi has access to serial ports ## NOTE: BASE_USER is defined by CustomPIOS Variable ## there for if you plan to set something else than "pi" ## Currently CustomPIOS uses "pi" -usermod -a -G ${KLIPPER_USER_GROUPS} ${BASE_USER} +usermod -a -G "${KLIPPER_USER_GROUPS}" "${BASE_USER}" -### clone klipper repo -pushd /home/${BASE_USER} +## Clone klipper repo +pushd "/home/${BASE_USER}" &> /dev/null || exit 1 gitclone KLIPPER_REPO klipper -### Create needed dirs -for dirs in ${KLIPPER_USER_DIRS}; do - if [ -d /home/$BASE_USER/$dirs ]; then - echo_green "$dirs already exists!" +## Create needed dirs +for dir in ${KLIPPER_USER_DIRS}; do + if [ -d "/home/${BASE_USER}/$dir" ]; then + echo_green "${dir} already exists!" else - echo_green "Creating $dirs" - sudo -u $BASE_USER mkdir -p $dirs + echo_green "Creating ${dir}" + sudo -u "${BASE_USER}" mkdir -p "${dir}" fi done -popd +popd &> /dev/null || exit 1 -# create python virtualenv and install klipper requirements -pushd /home/${BASE_USER} -echo_green "Creating Virtualenv for Klipper (klipper-env) ..." -sudo -u ${BASE_USER} virtualenv -p python2 ${KLIPPER_PYTHON_DIR} +## create python virtualenv and install klipper requirements +pushd "/home/${BASE_USER}" &> /dev/null || exit 1 +echo_green "Creating Virtualenv for Klipper (klippy-env) ..." +sudo -u "${BASE_USER}" virtualenv -p python3 "${KLIPPER_PYTHON_DIR}" echo_green "Installing klippy Python Dependencies ..." -sudo -u ${BASE_USER} ${KLIPPER_PYTHON_DIR}/bin/pip install -r ${KLIPPER_SRC_DIR}/${KLIPPER_PYENV_REQ} -popd +sudo -u "${BASE_USER}" "${KLIPPER_PYTHON_DIR}"/bin/pip install -r "${KLIPPER_SRC_DIR}"/"${KLIPPER_PYENV_REQ}" +popd &> /dev/null || exit 1 -# enable systemd service +## Enable systemd service systemctl_if_exists enable klipper.service + +## Done message +echo_green "Installing Klipper and enable klippy Service ... done!" diff --git a/src/modules/mainsailos/config b/src/modules/mainsailos/config index bc47fd421..04091d5bb 100644 --- a/src/modules/mainsailos/config +++ b/src/modules/mainsailos/config @@ -1,2 +1,4 @@ -# This file is intentionally left blank -# Preparation for later use cases +#!/bin/bash +# shellcheck disable=all + +[ -n "$MAINSAILOS_DEPS" ] || MAINSAILOS_DEPS="python3-serial" diff --git a/src/modules/mainsailos/start_chroot_script b/src/modules/mainsailos/start_chroot_script index 274ac5931..0acaef549 100644 --- a/src/modules/mainsailos/start_chroot_script +++ b/src/modules/mainsailos/start_chroot_script @@ -21,3 +21,8 @@ function get_parent { cat /etc/os-release | grep VERSION_CODENAME | cut -d '=' -f2 } echo "${DIST_NAME} release ${DIST_VERSION} ($(get_parent))" > /etc/${DIST_NAME,,}-release + +### Install CANBoot Dependency +apt update +# shellcheck disable=SC2086 +check_install_pkgs ${MAINSAILOS_DEPS} diff --git a/src/modules/mjpgstreamer/config b/src/modules/mjpgstreamer/config deleted file mode 100644 index c6f0d4870..000000000 --- a/src/modules/mjpgstreamer/config +++ /dev/null @@ -1,5 +0,0 @@ -[ -n "$MJPGSTREAMER_MJPGSTREAMER_REPO_SHIP" ] || MJPGSTREAMER_MJPGSTREAMER_REPO_SHIP=https://github.com/jacksonliam/mjpg-streamer.git -[ -n "$MJPGSTREAMER_MJPGSTREAMER_REPO_BUILD" ] || MJPGSTREAMER_MJPGSTREAMER_REPO_BUILD= -[ -n "$MJPGSTREAMER_MJPGSTREAMER_REPO_BRANCH" ] || MJPGSTREAMER_MJPGSTREAMER_REPO_BRANCH=master -[ -n "$MJPGSTREAMER_MJPGSTREAMER_REPO_DEPTH" ] || MJPGSTREAMER_MJPGSTREAMER_REPO_DEPTH=1 -[ -n "$MJPGSTREAMER_INCLUDE_MJPGSTREAMER" ] || MJPGSTREAMER_INCLUDE_MJPGSTREAMER=yes diff --git a/src/modules/mjpgstreamer/filesystem/home/pi/klipper_config/webcam.txt b/src/modules/mjpgstreamer/filesystem/home/pi/klipper_config/webcam.txt deleted file mode 100644 index e8bd44c72..000000000 --- a/src/modules/mjpgstreamer/filesystem/home/pi/klipper_config/webcam.txt +++ /dev/null @@ -1,79 +0,0 @@ -### Windows users: To edit this file use Notepad++, VSCode, Atom or SublimeText. -### Do not use Notepad or WordPad. - -### MacOSX users: If you use Textedit to edit this file make sure to use -### "plain text format" and "disable smart quotes" in "Textedit > Preferences" - -### Configure which camera to use -# -# Available options are: -# - auto: tries first usb webcam, if that's not available tries raspi cam -# - usb: only tries usb webcam -# - raspi: only tries raspi cam -# -# Defaults to auto -# -#camera="auto" - -### Additional options to supply to MJPG Streamer for the USB camera -# -# See https://faq.octoprint.org/mjpg-streamer-config for available options -# -# Defaults to a resolution of 640x480 px and a framerate of 10 fps -# -#camera_usb_options="-r 640x480 -f 10" - -### Additional webcam devices known to cause problems with -f -# -# Apparently there a some devices out there that with the current -# mjpg_streamer release do not support the -f parameter (for specifying -# the capturing framerate) and will just refuse to output an image if it -# is supplied. -# -# The webcam daemon will detect those devices by their USB Vendor and Product -# ID and remove the -f parameter from the options provided to mjpg_streamer. -# -# By default, this is done for the following devices: -# Logitech C170 (046d:082b) -# GEMBIRD (1908:2310) -# Genius F100 (0458:708c) -# Cubeternet GL-UPC822 UVC WebCam (1e4e:0102) -# -# Using the following option it is possible to add additional devices. If -# your webcam happens to show above symptoms, try determining your cam's -# vendor and product id via lsusb, activating the line below by removing # and -# adding it, e.g. for two broken cameras "aabb:ccdd" and "aabb:eeff" -# -# additional_brokenfps_usb_devices=("aabb:ccdd" "aabb:eeff") -# -# -#additional_brokenfps_usb_devices=() - -### Additional options to supply to MJPG Streamer for the RasPi Cam -# -# See https://faq.octoprint.org/mjpg-streamer-config for available options -# -# Defaults to 10fps -# -#camera_raspi_options="-fps 10" - -### Configuration of camera HTTP output -# -# Usually you should NOT need to change this at all! Only touch if you -# know what you are doing and what the parameters mean. -# -# Below settings are used in the mjpg-streamer call like this: -# -# -o "output_http.so -w $camera_http_webroot $camera_http_options" -# -# Current working directory is the mjpg-streamer base directory. -# -#camera_http_webroot="./www-mainsail" -#camera_http_options="-n" - -### EXPERIMENTAL -# Support for different streamer types. -# -# Available options: -# mjpeg [default] - stable MJPG-streamer -#camera_streamer=mjpeg diff --git a/src/modules/mjpgstreamer/filesystem/root/etc/logrotate.d/webcamd b/src/modules/mjpgstreamer/filesystem/root/etc/logrotate.d/webcamd deleted file mode 100644 index ecd9f7803..000000000 --- a/src/modules/mjpgstreamer/filesystem/root/etc/logrotate.d/webcamd +++ /dev/null @@ -1,12 +0,0 @@ - -/var/log/webcamd.log -{ - rotate 2 - weekly - maxsize 32M - missingok - notifempty - compress - delaycompress - sharedscripts -} diff --git a/src/modules/mjpgstreamer/filesystem/root/etc/systemd/system/webcamd.service b/src/modules/mjpgstreamer/filesystem/root/etc/systemd/system/webcamd.service deleted file mode 100644 index d5c121118..000000000 --- a/src/modules/mjpgstreamer/filesystem/root/etc/systemd/system/webcamd.service +++ /dev/null @@ -1,15 +0,0 @@ - -[Unit] -Description=the MainsailOS webcam daemon (based on OctoPi) with the user specified config - -[Service] -WorkingDirectory=/usr/local/bin -StandardOutput=append:/var/log/webcamd.log -StandardError=append:/var/log/webcamd.log -ExecStart=/usr/local/bin/webcamd -Restart=always -Type=forking -User=pi - -[Install] -WantedBy=multi-user.target diff --git a/src/modules/mjpgstreamer/filesystem/root/usr/local/bin/webcamd b/src/modules/mjpgstreamer/filesystem/root/usr/local/bin/webcamd deleted file mode 100755 index 7d3dbed2c..000000000 --- a/src/modules/mjpgstreamer/filesystem/root/usr/local/bin/webcamd +++ /dev/null @@ -1,303 +0,0 @@ -#!/bin/bash - -######################################################################## -### DO NOT EDIT THIS FILE TO CHANGE THE CONFIG!!! ### -### ---------------------------------------------------------------- ### -### There is no need to edit this file for changing resolution, ### -### frame rates or any other mjpg-streamer parameters. Please edit ### -### /home/pi/klipper_config/webcam.txt instead - that's what it's ### -### there for! You can even do this with your Pi powered down by ### -### directly accessing the file when using the SD card as thumb ### -### drive in your regular computer. ### -######################################################################## - -MJPGSTREAMER_HOME=/home/pi/mjpg-streamer -MJPGSTREAMER_INPUT_USB="input_uvc.so" -MJPGSTREAMER_INPUT_RASPICAM="input_raspicam.so" - -brokenfps_usb_devices=("046d:082b" "1908:2310" "0458:708c" "1e4e:0102" "0471:0311" "038f:6001" "046d:0804" "046d:0825" "046d:0994" "0ac8:3450") - -config_dir="/home/pi/klipper_config" - -echo "Starting up webcamDaemon..." -echo "" - -cfg_files=() -#cfg_files+=/boot/mainsail.txt -if [[ -d ${config_dir} ]]; then - cfg_files+=( `ls ${config_dir}/webcam*.txt` ) -fi - -array_camera_config=() -array_camera=() -array_camera_usb_options=() -array_camera_usb_device=() -array_camera_raspi_options=() -array_camera_http_webroot=() -array_camera_http_options=() -array_additional_brokenfps_usb_devices=() -array_camera_device=() -array_assigned_device=() - -echo "--- Configuration: ----------------------------" -for cfg_file in ${cfg_files[@]}; do - # init configuration - DO NOT EDIT, USE /home/pi/klipper_config/webcam*.txt INSTEAD! - camera="auto" - camera_usb_options="-r 640x480 -f 10" - camera_raspi_options="-fps 10" - camera_http_webroot="./www-mjpgstreamer" - camera_http_options="-n" - additional_brokenfps_usb_devices=() - - if [[ -e ${cfg_file} ]]; then - source "$cfg_file" - fi - usb_options="$camera_usb_options" - - # if webcam device is explicitly given in /home/pi/klipper_config/webcam*.txt, save the path of the device - # to a variable and remove its parameter from usb_options - extracted_device=`echo $usb_options | sed 's@.*-d \(/dev/\(video[0-9]\+\|v4l/[^ ]*\)\).*@\1@'` - if [ "$extracted_device" != "$usb_options" ] - then - # the camera options refer to a device, save it in a variable - # replace video device parameter with empty string and strip extra whitespace - usb_options=`echo $usb_options | sed 's/\-d \/dev\/\(video[0-9]\+\|v4l\/[^ ]*\)//g' | awk '$1=$1'` - else - extracted_device="" - fi - - # echo configuration - echo "cfg_file: $cfg_file" - echo "camera: $camera" - echo "usb options: $camera_usb_options" - echo "raspi options: $camera_raspi_options" - echo "http options: -w $camera_http_webroot $camera_http_options" - echo "" - echo "Explicitly USB device: $extracted_device" - echo "-----------------------------------------------" - echo "" - - array_camera_config+=( $cfg_file ) - array_camera+=( $camera ) - array_camera_usb_options+=("$usb_options") - array_camera_usb_device+=("$extracted_device") - array_camera_raspi_options+=("$camera_raspi_options") - array_camera_http_webroot+=("$camera_http_webroot") - array_camera_http_options+=("$camera_http_options") - array_camera_brokenfps_usb_devices+=("${brokenfps_usb_devices[*]} ${additional_brokenfps_usb_devices[*]}") - array_camera_device+=("") -done - -# check if array contains a string -function containsString() { - local e match="$1" - shift - for e; do [[ "$e" == "$match" ]] && return 0; done - return 1 -} - -# cleans up when the script receives a SIGINT or SIGTERM -function cleanup() { - # make sure that all child processed die when we die - local pids=$(jobs -pr) - [ -n "$pids" ] && kill $pids - exit 0 -} - -# says goodbye when the script shuts down -function goodbye() { - # say goodbye - echo "" - echo "Goodbye..." - echo "" -} - -# runs MJPG Streamer, using the provided input plugin + configuration -function runMjpgStreamer { - input=$1 - - # There are problems with 0x000137ab firmware on VL805 (Raspberry Pi 4}). - # Try to autodetect offending firmware and temporarily fix the issue - # by changing power management mode - echo "Checking for VL805 (Raspberry Pi 4)..." - if [[ -f /usr/bin/vl805 ]]; then - VL805_VERSION=$(/usr/bin/vl805) - VL805_VERSION=${VL805_VERSION#*: } - echo " - version 0x${VL805_VERSION} detected" - case "$VL805_VERSION" in - 00013701) - echo " - nothing to be done. It shouldn't cause USB problems." - ;; - 000137ab) - echo -e " - \e[31mThis version is known to cause problems with USB cameras.\e[39m" - echo -e " You may want to downgrade to 0x0013701." - echo -e " - [FIXING] Trying the setpci -s 01:00.0 0xD4.B=0x41 hack to mitigate the" - echo -e " issue. It disables ASPM L1 on the VL805. Your board may (or may not) get" - echo -e " slightly hotter. For details see:" - echo -e " https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=244421" - setpci -s 01:00.0 0xD4.B=0x41 - ;; - *) - echo " - unknown firmware version. Doing nothing." - ;; - esac - else - echo " - It seems that you don't have VL805 (Raspberry Pi 4)." - echo " There should be no problems with USB (a.k.a. select() timeout)" - fi - - pushd $MJPGSTREAMER_HOME > /dev/null 2>&1 - echo Running ./mjpg_streamer -o "output_http.so -w $camera_http_webroot $camera_http_options" -i "$input" - LD_LIBRARY_PATH=. ./mjpg_streamer -o "output_http.so -w $camera_http_webroot $camera_http_options" -i "$input" & - sleep 1 & - sleep_pid=$! - wait ${sleep_pid} - popd > /dev/null 2>&1 -} - -# starts up the RasPiCam -function startRaspi { - logger -s "Starting Raspberry Pi camera" - runMjpgStreamer "$MJPGSTREAMER_INPUT_RASPICAM $camera_raspi_options" -} - -# starts up the USB webcam -function startUsb { - options="$usb_options" - device="video0" - - # check for parameter and set the device if it is given as a parameter - input=$1 - if [[ -n $input ]]; then - device=`basename "$input"` - fi - - # add video device into options - options="$options -d /dev/$device" - - uevent_file="/sys/class/video4linux/$device/device/uevent" - if [ -e $uevent_file ]; then - # let's see what kind of webcam we have here, fetch vid and pid... - product=`cat $uevent_file | grep PRODUCT | cut -d"=" -f2` - vid=`echo $product | cut -d"/" -f1` - pid=`echo $product | cut -d"/" -f2` - vidpid=`printf "%04x:%04x" "0x$vid" "0x$pid"` - - # ... then look if it is in our list of known broken-fps-devices and if so remove - # the -f parameter from the options (if it's in there, else that's just a no-op) - for identifier in ${brokenfps_usb_devices[@]}; - do - if [ "$vidpid" = "$identifier" ]; then - echo - echo "Camera model $vidpid is known to not work with -f parameter, stripping it out" - echo - options=`echo $options | sed -e "s/\(\s\+\|^\)-f\s\+[0-9]\+//g"` - fi - done - fi - - logger -s "Starting USB webcam" - runMjpgStreamer "$MJPGSTREAMER_INPUT_USB $options" -} - -# make sure our cleanup function gets called when we receive SIGINT, SIGTERM -trap "cleanup" SIGINT SIGTERM -# say goodbye when we EXIT -trap "goodbye" EXIT - -# we need this to prevent the later calls to vcgencmd from blocking -# I have no idea why, but that's how it is... -vcgencmd version > /dev/null 2>&1 - -# keep mjpg streamer running if some camera is attached -while true; do - - # get list of usb video devices into an array - video_devices=($(find /dev -regextype sed -regex '\/dev/video[0-9]\+' | sort -nk1.11 2> /dev/null)) - - # add list of raspi camera into an array - if [ "`vcgencmd get_camera`" = "supported=1 detected=1" ]; then - video_devices+=( "raspi" ) - fi - - echo "Found video devices:" - printf '%s\n' "${video_devices[@]}" - - for scan_mode in "usb" "usb-auto" "raspi" "auto"; do - camera=$scan_mode - if [[ "usb-auto" == "$scan_mode" ]]; then - camera="usb" - fi - for ((i=0;i<${#array_camera[@]};i++)); do - if [[ -z ${array_camera_device[${i}]} ]] && [[ $camera == ${array_camera[${i}]} ]]; then - camera_config="${array_camera_config[${i}]}" - usb_options="${array_camera_usb_options[${i}]}" - camera_usb_device="${array_camera_usb_device[${i}]}" - camera_raspi_options="${array_camera_raspi_options[${i}]}" - camera_http_webroot="${array_camera_http_webroot[${i}]}" - camera_http_options="${array_camera_http_options[${i}]}" - brokenfps_usb_devices="${array_camera_brokenfps_usb_devices[${i}]}" - if [[ ${camera_usb_device} ]] && { [[ "usb" == ${scan_mode} ]] || [[ "auto" == ${scan_mode} ]]; }; then - # usb device is explicitly set in options - usb_device_path=`readlink -f ${camera_usb_device}` - if containsString "$usb_device_path" "${array_camera_device[@]}"; then - if [[ "auto" != ${scan_mode} ]]; then - array_camera_device[${i}]="alredy_in_use" - echo "config file='$camera_config':Video device already in use." - continue - fi - elif containsString "$usb_device_path" "${video_devices[@]}"; then - array_camera_device[${i}]="$usb_device_path" - # explicitly set usb device was found in video_devices array, start usb with the found device - echo "config file='$camera_config':USB device was set in options and found in devices, start MJPG-streamer with the configured USB video device: $usb_device_path" - startUsb "$usb_device_path" - continue - fi - elif [[ -z ${camera_usb_device} ]] && { [[ "usb-auto" == ${scan_mode} ]] || [[ "auto" == ${scan_mode} ]]; }; then - for video_device in "${video_devices[@]}"; do - if [[ "raspi" != "$video_device" ]]; then - if containsString "$video_device" "${array_camera_device[@]}"; then - : #already in use - else - array_camera_device[${i}]="$video_device" - # device is not set explicitly in options, start usb with first found usb camera as the device - echo "config file='$camera_config':USB device was not set in options, start MJPG-streamer with the first found video device: ${video_device}" - startUsb "${video_device}" - break - fi - fi - done - if [[ -n ${array_camera_device[${i}]} ]]; then - continue - fi - fi - if [[ "raspi" == ${scan_mode} ]] || [[ "auto" == ${scan_mode} ]]; then - video_device="raspi" - if containsString "$video_device" "${array_camera_device[@]}"; then - if [[ "auto" != ${scan_mode} ]]; then - array_camera_device[${i}]="alredy_in_use" - echo "config file='$camera_config':RasPiCam device already in use." - fi - elif containsString "$video_device" "${video_devices[@]}"; then - array_camera_device[${i}]="$video_device" - echo "config file='$camera_config':Start MJPG-streamer with video device: ${video_device}" - startRaspi - sleep 30 & - sleep_pid=$! - wait ${sleep_pid} - fi - fi - fi - done - done - array_assigned_device=( ${array_camera_device[*]} ) - if [[ ${#array_camera[@]} -eq ${#array_assigned_device[@]} ]]; then - echo "Done bring up all configured video device" - exit 0 - else - echo "Scan again in two minutes" - sleep 120 & - sleep_pid=$! - wait ${sleep_pid} - fi -done diff --git a/src/modules/mjpgstreamer/start_chroot_script b/src/modules/mjpgstreamer/start_chroot_script deleted file mode 100644 index 377286ba5..000000000 --- a/src/modules/mjpgstreamer/start_chroot_script +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env bash -# MJPGstreamer installer -# Builds MJPGstreamer for rPi devices -# Written by Raymond Himle (Adapted from the OctoPi image creation scripts. Thanks Gina and Guysoft!) -# GPL V3 -######## - - -# Source error handling, leave this in place -set -x -set -e - -source /common.sh -install_cleanup_trap - -unpack /filesystem/home/${BASE_USER} /home/${BASE_USER} ${BASE_USER} - -apt update -apt install -y --allow-downgrades git cmake=3.13.4-1 cmake-data=3.13.4-1 -cd /home/${BASE_USER} - #mjpg-streamer - if [ "$MJPGSTREAMER_INCLUDE_MJPGSTREAMER" == "yes" ] - then - echo "--- Installing mjpg-streamer" - if [ $( is_in_apt libjpeg62-turbo-dev ) -eq 1 ]; then - apt-get -y --force-yes install libjpeg62-turbo-dev - elif [ $( is_in_apt libjpeg8-dev ) -eq 1 ]; then - apt-get -y --force-yes install libjpeg8-dev - fi - - apt-get -y --allow-downgrades --allow-remove-essential --allow-change-held-packages --no-install-recommends install imagemagick ffmpeg libv4l-dev - gitclone MJPGSTREAMER_MJPGSTREAMER_REPO mjpg-streamer - pushd mjpg-streamer - mv mjpg-streamer-experimental/* . - - # As said in Makefile, it is just a wrapper around CMake. - # To apply -j option, we have to unwrap it. - MJPG_STREAMER_BUILD_DIR=_build - [ -d ${MJPG_STREAMER_BUILD_DIR} ] || (mkdir ${MJPG_STREAMER_BUILD_DIR} && \ - chown ${BASE_USER}:${BASE_USER} ${MJPG_STREAMER_BUILD_DIR}) - [ -f ${MJPG_STREAMER_BUILD_DIR}/Makefile ] || (cd ${MJPG_STREAMER_BUILD_DIR} && \ - sudo -u ${BASE_USER} cmake -DCMAKE${MJPG_STREAMER_BUILD_DIR}_TYPE=Release ..) - - sudo -u ${BASE_USER} make -j $(nproc) -C ${MJPG_STREAMER_BUILD_DIR} - - sudo -u ${BASE_USER} cp ${MJPG_STREAMER_BUILD_DIR}/mjpg_streamer . - sudo -u ${BASE_USER} find ${MJPG_STREAMER_BUILD_DIR} -name "*.so" -type f -exec cp {} . \; - - # create our custom web folder and add a minimal index.html to it - sudo -u ${BASE_USER} mkdir www-mjpgstreamer - pushd www-mjpgstreamer - cat <> index.html - -mjpg_streamer test page - -

Snapshot

-

Refresh the page to refresh the snapshot

-Snapshot -

Stream

-Stream - - -EOT - popd - popd - fi - -### mjpg_streamer - -unpack /filesystem/root / - -if [ "$MJPGSTREAMER_INCLUDE_MJPGSTREAMER" == "yes" ] -then - systemctl_if_exists enable webcamd.service -else - rm /etc/logrotate.d/webcamd - rm /etc/systemd/system/webcamd.service - rm /root/bin/webcamd -fi - -#cleanup -apt-get clean -apt-get autoremove -y - -# link logfiles to klipper_logs -ln -s /var/log/webcamd.log /home/${BASE_USER}/klipper_logs/ - -# Run installation steps defined above - -# Unpack root at the end, so files are modified before -unpack /filesystem/root / diff --git a/src/modules/moonraker/filesystem/home/pi/klipper_config/moonraker.conf b/src/modules/moonraker/filesystem/home/pi/klipper_config/moonraker.conf index ef8366511..a874d816d 100644 --- a/src/modules/moonraker/filesystem/home/pi/klipper_config/moonraker.conf +++ b/src/modules/moonraker/filesystem/home/pi/klipper_config/moonraker.conf @@ -33,9 +33,15 @@ trusted_clients: # enables moonraker to track and store print history. [history] +# this enables moonraker announcements for mainsail +[announcements] +subscriptions: + mainsail + # this enables moonraker's update manager [update_manager] refresh_interval: 168 +enable_auto_refresh: True [update_manager mainsail] type: web diff --git a/src/modules/piconfig/filesystem/root/boot/config.txt b/src/modules/piconfig/filesystem/root/boot/config.txt index 339f0dc24..5748a7a19 100644 --- a/src/modules/piconfig/filesystem/root/boot/config.txt +++ b/src/modules/piconfig/filesystem/root/boot/config.txt @@ -56,29 +56,60 @@ dtparam=spi=on # Enable audio (loads snd_bcm2835) dtparam=audio=on + +#################################################### +#### MainsailOS specific configurations #### +#################################################### +#### DO NOT CHANGE SECTION BELOW !!! #### +#### UNLESS YOU KNOW WHAT YOU ARE DOING !!! #### +#################################################### + +## For more options and information see +## https://www.raspberrypi.com/documentation/computers/config_txt.html +## Some settings may impact device functionality. See link above for details + +## For additional information about device filters see +## https://www.raspberrypi.com/documentation/computers/config_txt.html#model-filters + + +[pi0] +## This affects Pi Zero(W) and Pi Zero2 +## Due lag of RAM, limit GPU RAM +gpu_mem=128 + +[pi2] +gpu_mem=256 + +[pi3] +## Use 256 if 1Gb Ram Model! +gpu_mem=128 +# gpu_mem=256 + [pi4] -# Enable DRM VC4 V3D driver on top of the dispmanx display stack +## Enable DRM VC4 V3D driver on top of the dispmanx display stack dtoverlay=vc4-fkms-v3d max_framebuffers=2 -# Do not use more than 256Mb on Pi Model 4, it uses its own Management. +## Do not use more than 256Mb on Pi Model 4, it uses its own Management. gpu_mem=256 [all] -#dtoverlay=vc4-fkms-v3d -# Enable Hardware UART for Serial Communication +## SPI Interface is enabled by default for Input Shaper +## To revert that comment out line #48 +## This colides with Hyperpixel Display! +## Hyperpixel Screen uses the same Pin for Backlight. + +## Enable Hardware UART for Serial Communication enable_uart=1 dtoverlay=disable-bt -# Enable Raspicam devices at boot +## Enable VideoCore at boot, needed for Raspicams and DSI devices. start_x=1 -gpu_mem=256 - -## Zero Models need special handling -[pi0w] -dtoverlay=pi3-disable-bt -gpu_mem=128 -[pi02] -gpu_mem=128 +### EXPERIMENTAL - Enable 64bit Kernel +### The 64-bit kernel will only work on: +### Raspberry Pi 3, 3+, 4, 400, Zero 2 W and 2B rev 1.2 +### and Raspberry Pi Compute Modules 3, 3+ and 4. +# arm_64bit=1 +#################################################### diff --git a/src/modules/postrename/config b/src/modules/postrename/config new file mode 100644 index 000000000..64222e8b6 --- /dev/null +++ b/src/modules/postrename/config @@ -0,0 +1,12 @@ +#!/bin/bash +#### Post Rename +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 +#### https://github.com/mainsail-crew/MainsailOS +#### +#### This File is distributed under GPLv3 +#### +# shellcheck disable=all + +# Intentionaly left blank diff --git a/src/modules/postrename/filesystem/root/postrename b/src/modules/postrename/filesystem/root/postrename new file mode 100644 index 000000000..dab0f55dc --- /dev/null +++ b/src/modules/postrename/filesystem/root/postrename @@ -0,0 +1,207 @@ +#!/bin/bash +#### Post Rename +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 +#### https://github.com/mainsail-crew/MainsailOS +#### +#### This File is distributed under GPLv3 +#### + +## Error handling +set -e + +# Colored Output +RED="\e[31m" +YEL="\e[33m" +GRE="\e[32m" +WHITE="\e[97m" +NOC="\e[0m" + +### Setup +SERVICES=(moonraker klipper nginx sonar crowsnest) +SYSTEMD_DIR="/etc/systemd/system" +DEFAULT_USER="$(grep "1000" /etc/passwd | awk -F ':' '{print $1}')" + + +## Helper funcs +### Mangle services +function stop_services { + for srv in "${SERVICES[@]}"; do + if [ "$(systemctl is-active "${srv}.service")" != "inactive" ]; then + systemctl stop "${srv}.service" + fi + done +} + +function start_services { + for srv in "${SERVICES[@]}"; do + systemctl start "${srv}.service" + done +} + +### Clean up +function cleanup { + # Cleanup self + rm -rf "${0}" + # Cleanup rc.local + sed -i '/\/postrename/d' /etc/rc.local +} + +### Change nginx root +function change_www_root { + bash -c " + sed -i 's|/home/pi/mainsail|/home/${DEFAULT_USER}/mainsail|g' \ + /etc/nginx/sites-available/mainsail + " +} + + +### change username in service files +function change_service_user { + ### Filter nginx service first! + local -a servicefile + servicefile=( "${SERVICES[@]/nginx}" ) + + for i in "${servicefile[@]}"; do + if [ -n "${i}" ]; then + sed -i 's/pi/'"${DEFAULT_USER}"'/g' "${SYSTEMD_DIR}/${i}.service" + fi + done +} + +function relocate_venv { + local -a venvs + venvs=(klippy-env moonraker-env) + + for venv in "${venvs[@]}"; do + sudo -u "${DEFAULT_USER}" \ + virtualenv --relocatable -p /usr/bin/python3 "/home/${DEFAULT_USER}/${venv}" + done +} + +function patch_polkit_rules { + local polkit_dir polkit_legacy_dir polkit_usr_dir + polkit_legacy_dir="/etc/polkit-1/localauthority/50-local.d" + polkit_dir="/etc/polkit-1/rules.d" + polkit_usr_dir="/usr/share/polkit-1/rules.d" + if [ -f "${polkit_dir}/moonraker.rules" ]; then + sed -i 's/pi/'"${DEFAULT_USER}"'/g' "${polkit_dir}/moonraker.rules" + fi + if [ -f "${polkit_usr_dir}/moonraker.rules" ]; then + sed -i 's/pi/'"${DEFAULT_USER}"'/g' "${polkit_usr_dir}/moonraker.rules" + fi + if [ -f "${polkit_legacy_dir}/10-moonraker.pkla" ]; then + sed -i 's/pi/'"${DEFAULT_USER}"'/g' "${polkit_legacy_dir}/10-moonraker.pkla" + fi +} + +function patch_cn_logrotate { + if [ -f "/etc/logrotate.d/crowsnest" ]; then + sed -i 's/pi/'"${DEFAULT_USER}"'/g' "/etc/logrotate.d/crowsnest" + fi +} + +## Fix broken links +function fix_broken_links { + local -a brokenlinks + local path + brokenlinks=(crowsnest sonar) + path="/usr/local/bin" + + for bl in "${brokenlinks[@]}"; do + if [ -h "${path}/${bl}" ]; then + rm -rf "${path:?}/${bl}" + fi + find "/home/${DEFAULT_USER}" -type f -iname "${bl}" -print0 | \ + xargs -0 -I {} ln -s {} "${path}/${bl}" + done +} + +function fix_timelapse_links { + local config_dir src_dir target_dir + config_dir="/home/${DEFAULT_USER}/klipper_config" + src_dir="/home/${DEFAULT_USER}/moonraker-timelapse" + target_dir="/home/${DEFAULT_USER}/moonraker/moonraker/components" + sudo -u "${DEFAULT_USER}" \ + ln -sf "${src_dir}/component/timelapse.py" "${target_dir}/timelapse.py" + sudo -u "${DEFAULT_USER}" \ + ln -sf "${src_dir}/klipper_macro/timelapse.cfg" "${config_dir}/timelapse.cfg" +} + +function main { +local cmdltxt +cmdltxt="/boot/cmdline.txt" + +## Make sure init_resize.sh and firstrun.sh are finished +if [ "$(grep -c "init" "${cmdltxt}")" != "0" ] && \ +[ "$(grep -c "systemd.run.*" "${cmdltxt}")" != "0" ]; then + echo -e "[${RED}ERROR${NOC}] \ + ${WHITE}Sdcard resize and firtrun are not finished yet ... [ABORT]${NOC}" + ## Make sure not failing rc.local + return 0 +fi +## Abort if user = pi +if [ "${DEFAULT_USER}" == "pi" ]; then + echo -e "[${YEL}SKIPPED${NOC}] \ + ${WHITE}User is ${DEFAULT_USER}! Nothing to do ...${NOC}" + cleanup + exit 0 +fi + +echo -e "\n\t${WHITE}Trying to fix user rename ...${NOC}" +## Stop services +echo -en "${WHITE}Stopping all related services ...${NOC}\r" +stop_services +echo -e "${WHITE}Stopping all related services ...${NOC}[${GRE}OK${NOC}]" +## Change www root +echo -en "${WHITE}Try changing path of nginx root ...${NOC}\r" +change_www_root +echo -e "${WHITE}Try changing path of nginx root ...${NOC}[${GRE}OK${NOC}]" +## patch service files +echo -en "${WHITE}Patching service files ...${NOC}\r" +change_service_user +echo -e "${WHITE}Patching service files ...${NOC}[${GRE}OK${NOC}]" +## relocate venvs +echo -e "${WHITE}Trying to relocate venv's ...${NOC}" +relocate_venv +echo -e "${WHITE}Trying to relocate venv's ...${NOC}[${GRE}OK${NOC}]" +## patch polkit rules +echo -e "${WHITE}Patching moonraker's polkit rules ...${NOC}" +patch_polkit_rules +echo -e "${WHITE}Patching moonraker's polkit rules ...${NOC}[${GRE}OK${NOC}]" +## patch crowsnest logrotate +echo -e "${WHITE}Patching crowsnest logrotate ...${NOC}" +patch_cn_logrotate +echo -e "${WHITE}Patching crowsnest logrotate ...${NOC}[${GRE}OK${NOC}]" +## fix broken links +echo -en "${WHITE}Fix broken symlinks ...${NOC}\r" +fix_broken_links +fix_timelapse_links +echo -e "${WHITE}Fix broken symlinks ...${NOC}[${GRE}OK${NOC}]" +## do a short break +sleep 2 +## reload daemons +echo -en "${WHITE}Apply service file changes ...${NOC}\r" +systemctl daemon-reload +echo -e "${WHITE}Apply service file changes ...${NOC}[${GRE}OK${NOC}]" +## do a short break +sleep 2 +## restart services +echo -e "${WHITE}Trying to restart services ...${NOC}" +start_services +## wait 30sec to come up +echo -e "${WHITE}Waiting for service restart completed ...${NOC}" +sleep 30 +## Cleanup +echo -e "${WHITE}Cleanup files, remove postrename ...${NOC}" +cleanup +sleep 2 +## reboot system +echo -e "${WHITE}Reboot system ...${NOC}" +reboot +} + +### MAIN +main +exit 0 diff --git a/src/modules/postrename/start_chroot_script b/src/modules/postrename/start_chroot_script new file mode 100644 index 000000000..8ea8937da --- /dev/null +++ b/src/modules/postrename/start_chroot_script @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +#!/bin/bash +#### Post Rename +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2021 +#### https://github.com/mainsail-crew/MainsailOS +#### +#### This File is distributed under GPLv3 +#### +# shellcheck disable=all + +# Source error handling, leave this in place +set -xe + +# Source CustomPIOS common.sh +source /common.sh +install_cleanup_trap + +## unpack postrename +unpack filesystem/root / root +## set executable +sudo chmod 0755 /postrename + +## run postrename via rc.local +sed -i 's@exit 0@@' /etc/rc.local +echo -e "/postrename\nexit 0\n" | tee -a /etc/rc.local diff --git a/src/modules/sonar/config b/src/modules/sonar/config new file mode 100644 index 000000000..0e350bd8e --- /dev/null +++ b/src/modules/sonar/config @@ -0,0 +1,21 @@ +#!/bin/bash +#### Sonar - A WiFi Keepalive daemon +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2022 +#### https://github.com/mainsail-crew/sonar +#### +#### This File is distributed under GPLv3 +#### +# shellcheck disable=all + +# Sonar +[ -n "$SONAR_REPO_SHIP" ] || SONAR_REPO_SHIP=https://github.com/mainsail-crew/sonar.git +[ -n "$SONAR_REPO_BRANCH" ] || SONAR_REPO_BRANCH=main +[ -n "$SONAR_DEPS" ] || SONAR_DEPS="git crudini iputils-ping" +[ -n "$SONAR_DEFAULT_CONF_DIR" ] || SONAR_DEFAULT_CONF_DIR="/home/${BASE_USER}/klipper_config" +[ -n "$SONAR_DEFAULT_CONF" ] || SONAR_DEFAULT_CONF="mainsail_default.conf" +# Add Sonar to moonraker.conf (update_manager) bool (1:yes / 0:no) +[ -n "$SONAR_ADD_SONAR_MOONRAKER" ] || SONAR_ADD_SONAR_MOONRAKER=1 +# Path to moonraker.conf (must be set if add to update_manager) +[ -n "$SONAR_MOONRAKER_CONF" ] || SONAR_MOONRAKER_CONF="${SONAR_DEFAULT_CONF_DIR}/moonraker.conf" diff --git a/src/modules/sonar/start_chroot_script b/src/modules/sonar/start_chroot_script new file mode 100644 index 000000000..5ca66588f --- /dev/null +++ b/src/modules/sonar/start_chroot_script @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +#### Sonar - A WiFi Keepalive daemon +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2022 +#### https://github.com/mainsail-crew/sonar +#### +#### This File is distributed under GPLv3 +#### + +# shellcheck enable=require-variable-braces + +## Source error handling, leave this in place +set -Eex + +## Set LC_ALL to prevent errors +export LC_ALL=C + +# Set DEBIAN_FRONTEND to noninteractive +if [ "${DEBIAN_FRONTEND}" != "noninteractive" ]; then + export DEBIAN_FRONTEND=noninteractive +fi + +## Source CustomPIOS common.sh +# shellcheck disable=SC1091 +source /common.sh +install_cleanup_trap + +# Setup template file +MOONRAKER_TEMPLATE="/home/${BASE_USER}/sonar/file_templates/moonraker_update.txt" + +## helper func moonraker update_manager +function add_update_entry { + if [ -f "${SONAR_MOONRAKER_CONF}" ]; then + if [ -f "/tmp/moonraker.conf" ]; then + rm -rf /tmp/moonraker.conf + fi + sudo -u "${BASE_USER}" \ + cat "${SONAR_MOONRAKER_CONF}" "${MOONRAKER_TEMPLATE}" | \ + tee /tmp/moonraker.conf > /dev/null && + cp -rf /tmp/moonraker.conf "${SONAR_MOONRAKER_CONF}" + fi +} + +echo_green "Installing sonar and enable sonar Service ..." + +## Install all deps at once for time consumption reasons. +## APT: Update Repo Database and install Dependencies +# Force apt update +apt update +echo_green "Installing Sonar Dependencies ..." +# shellcheck disable=SC2086 +## Disabling shellcheck SC2086, because we want "wordsplitting" +check_install_pkgs ${SONAR_DEPS} +## Move to $HOME dir +pushd "/home/${BASE_USER}" &> /dev/null || exit 1 + ## clone Repo + echo_green "Clone sonar repository ..." + gitclone SONAR_REPO sonar + ## Install sonar, using builtin installer + pushd "/home/${BASE_USER}/sonar" &> /dev/null || exit 1 + echo_green "Running sonar installer ..." + sudo -u "${BASE_USER}" make unattended + ## Make sure config dir exits + if [ ! -d "${SONAR_DEFAULT_CONF_DIR}" ]; then + sudo -u "${BASE_USER}" mkdir -p "${SONAR_DEFAULT_CONF_DIR}" + fi + ## Copy default config + echo_green "Copying default config file ..." + sudo -u "${BASE_USER}" \ + cp "${PWD}/sample_config/${SONAR_DEFAULT_CONF}" \ + "${SONAR_DEFAULT_CONF_DIR}/sonar.conf" + + ## Add moonraker update_manager + if [ "${SONAR_ADD_SONAR_MOONRAKER}" == "1" ]; then + echo -en "Adding Sonar Update Manager entry to moonraker.conf ...\r" + add_update_entry + echo -e "Adding Sonar Update Manager entry to moonraker.conf ... [OK]" + fi + popd &> /dev/null || exit 1 +popd &> /dev/null || exit 1 + +## Done message +echo_green "Installing sonar and enable sonar Service ... done!" diff --git a/src/modules/timelapse/config b/src/modules/timelapse/config new file mode 100644 index 000000000..ad56380f4 --- /dev/null +++ b/src/modules/timelapse/config @@ -0,0 +1,16 @@ +#!/bin/bash +# moonraker-timelapse custompios module +# https://github.com/mainsail-crew/moonraker-timelapse +# written by Stephan Wendel aka KwadFan +# +# GPL V3 +######## +# shellcheck disable=all +[ -n "$TIMELAPSE_SRC_DIR" ] || TIMELAPSE_SRC_DIR="/home/${BASE_USER}/moonraker-timelapse" +[ -n "$TIMELAPSE_PYTHON_DIR" ] || TIMELAPSE_TARGET_DIR="/home/${BASE_USER}/moonraker/moonraker/components" +[ -n "$TIMELAPSE_CONFIG_DIR" ] || TIMELAPSE_CONFIG_DIR="/home/${BASE_USER}/klipper_config" +[ -n "$TIMELAPSE_TEMPLATE" ] || TIMELAPSE_TEMPLATE="/home/${BASE_USER}/klipper_config/timelapse_template.txt" + +[ -n "$TIMELAPSE_REPO_SHIP" ] || TIMELAPSE_REPO_SHIP=https://github.com/mainsail-crew/moonraker-timelapse.git +[ -n "$TIMELAPSE_REPO_BRANCH" ] || TIMELAPSE_REPO_BRANCH=main +[ -n "$TIMELAPSE_DEPS" ] || TIMELAPSE_DEPS="ffmpeg" diff --git a/src/modules/timelapse/filesystem/home/pi/klipper_config/timelapse_template.txt b/src/modules/timelapse/filesystem/home/pi/klipper_config/timelapse_template.txt new file mode 100644 index 000000000..910ab0e16 --- /dev/null +++ b/src/modules/timelapse/filesystem/home/pi/klipper_config/timelapse_template.txt @@ -0,0 +1,13 @@ + +### moonraker-timelapse +### Don't forget to include timelapse.cfg to your printer.cfg +### Uncomment to enable moonraker-timelapse + +#[timelapse] + +#[update_manager timelapse] +#type: git_repo +#primary_branch: main +#path: ~/moonraker-timelapse +#origin: https://github.com/mainsail-crew/moonraker-timelapse.git +#managed_services: klipper moonraker diff --git a/src/modules/timelapse/start_chroot_script b/src/modules/timelapse/start_chroot_script new file mode 100644 index 000000000..ac985d168 --- /dev/null +++ b/src/modules/timelapse/start_chroot_script @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +#### MainsailOS Build Chain +#### +#### moonraker-timelapse install module +#### #!/bin/bash +#### https://github.com/mainsail-crew/moonraker-timelapse +#### +#### Written by Stephan Wendel aka KwadFan +#### Copyright 2022 +#### https://github.com/mainsail-crew/MainsailOS +#### +#### This File is distributed under GPLv3 +#### + +###### THIS MODULE HAS TO BE PLACED RIGHT AFTER "moonraker" MODULE!!! + +# shellcheck enable=require-variable-braces + +## Source error handling, leave this in place +set -Eex + +## Set LC_ALL to prevent errors +export LC_ALL=C + +# Set DEBIAN_FRONTEND to noninteractive +if [ "${DEBIAN_FRONTEND}" != "noninteractive" ]; then + export DEBIAN_FRONTEND=noninteractive +fi + +## Source CustomPIOS common.sh +# shellcheck disable=SC1091 +source /common.sh +install_cleanup_trap + +## helper func moonraker update_manager +function add_timelapse_entry { + if [ -f "${TIMELAPSE_CONFIG_DIR}/moonraker.conf" ]; then + if [ -f "/tmp/moonraker.conf" ]; then + rm -rf /tmp/moonraker.conf + fi + sudo -u "${BASE_USER}" \ + cat "${TIMELAPSE_CONFIG_DIR}/moonraker.conf" "${TIMELAPSE_TEMPLATE}" | \ + tee /tmp/moonraker.conf > /dev/null && + cp -rf /tmp/moonraker.conf "${TIMELAPSE_CONFIG_DIR}/moonraker.conf" + fi + ## Cleanup template + if [ -f "${TIMELAPSE_TEMPLATE}" ]; then + rm -f "${TIMELAPSE_TEMPLATE}" + fi +} + +echo_green "Installing moonraker-timelapse plugin ..." + +### Install template file +unpack /filesystem/home/${BASE_USER} /home/${BASE_USER} ${BASE_USER} + +## Install all deps at once for time consumption reasons. +## APT: Update Repo Database and install Dependencies +# Force apt update +apt update +echo_green "Installing moonraker-timelapse Dependencies ..." +## Disabling shellcheck SC2086, because we want "wordsplitting" +# shellcheck disable=SC2086 +check_install_pkgs ${TIMELAPSE_DEPS} + + +## Clone klipper repo +pushd "/home/${BASE_USER}" &> /dev/null || exit 1 +gitclone TIMELAPSE_REPO moonraker-timelapse + +## Link component +if [ -d "${TIMELAPSE_TARGET_DIR}" ]; then + echo "Linking extension to moonraker ..." + sudo -u "${BASE_USER}" \ + ln -sf "${TIMELAPSE_SRC_DIR}/component/timelapse.py" "${TIMELAPSE_TARGET_DIR}/timelapse.py" +fi + +## Link timelapse.cfg +if [ -d "/home/${BASE_USER}/klipper_config" ]; then + echo "Linking macro file ..." + sudo -u "${BASE_USER}" \ + ln -sf "${TIMELAPSE_SRC_DIR}/klipper_macro/timelapse.cfg" "${TIMELAPSE_CONFIG_DIR}/timelapse.cfg" +fi + +## Extend moonraker.conf +echo "Modifying moonraker.conf ..." +add_timelapse_entry + + +popd || exit 1 + + +## Done message +echo_green "Installing moonraker-timelapse plugin ... done!"