#!/bin/bash detect_camera() { echo echo echo "Verify the camera is currently unplugged from USB....." if prompt_confirm "Is the camera you are trying to detect unplugged from USB?"; then readarray -t c1 < <(ls -1 /dev/v4l/by-id/*index0 2>/dev/null) fi dmesg -C echo "Plug your camera in via USB now (detection time-out in 1 min)" counter=0 while [[ -z "$CAM" ]] && [[ $counter -lt 60 ]]; do CAM=$(dmesg | sed -n -e 's/^.*SerialNumber: //p') TEMPUSBCAM=$(dmesg | sed -n -e 's|^.*input:.*/\(.*\)/input/input.*|\1|p') counter=$(( $counter + 1 )) if [[ -n "$TEMPUSBCAM" ]] && [[ -z "$CAM" ]]; then break fi sleep 1 done readarray -t c2 < <(ls -1 /dev/v4l/by-id/*index0 2>/dev/null) #https://stackoverflow.com/questions/2312762 #TODO: what if there is more than one element? BYIDCAM=(`echo ${c2[@]} ${c1[@]} | tr ' ' '\n' | sort | uniq -u `) echo $BYIDCAM dmesg -C } remove_camera() { systemctl stop $1.service systemctl disable $1.service rm /etc/systemd/system/$1.service 2>/dev/null rm /etc/$1.env 2>/dev/null sed -i "/$1/d" /etc/udev/rules.d/99-octoprint.rules sed -i "/$1/d" /etc/octoprint_cameras if [ "$HAPROXY" == true ]; then sed -i "/use_backend $1/d" /etc/haproxy/haproxy.cfg sed -i "/#$1 start/,/#$1 stop/d" /etc/haproxy/haproxy.cfg systemctl restart haproxy fi } write_camera() { get_settings if [ -z "$STREAMER" ]; then STREAMER="ustreamer" fi if [ -n "$BYIDCAM" ] && [ -z "$CAM" ] && [ -z "$TEMPUSBCAM" ]; then CAMDEVICE=$BYIDCAM else CAMDEVICE=/dev/cam${INUM}_$INSTANCE fi OUTFILE=cam${INUM}_$INSTANCE #mjpg-streamer if [ "$STREAMER" == mjpg-streamer ]; then cat $SCRIPTDIR/octocam_mjpg.service | \ -e "s/OCTOCAM/$CAMDEVICE/" \ -e "s/RESOLUTION/$RESOLUTION/" \ -e "s/FRAMERATE/$FRAMERATE/" \ -e "s/CAMPORT/$CAMPORT/" > $SCRIPTDIR/cam${INUM}_$INSTANCE.service fi #ustreamer if [ "$STREAMER" == ustreamer ]; then if [ "$PI" == true ]; then cat $SCRIPTDIR/octocam_ustream.service | \ -e "s/OCTOCAM/cam${INUM}_$INSTANCE/" \ -e "s|ExecStart=|ExecStart=/usr/bin/libcamerify |" > $SCRIPTDIR/$OUTFILE.service else cat $SCRIPTDIR/octocam_ustream.service | \ -e "s/OCTOCAM/cam${INUM}_$INSTANCE/" > $SCRIPTDIR/$OUTFILE.service fi fi #camera-streamer if [ "$STREAMER" == camera-streamer ]; then if [ "$PI" == true ]; then cat $SCRIPTDIR/picam_camstream.service | \ -e "s/OCTOCAM/cam${INUM}_$INSTANCE/" > $SCRIPTDIR/$OUTFILE.service else cat $SCRIPTDIR/octocam_camstream.service | \ -e "s/OCTOCAM/cam${INUM}_$INSTANCE/" > $SCRIPTDIR/$OUTFILE.service fi fi #convert RES into WIDTH and HEIGHT for camera-streamer CAMWIDTH=$(sed -r 's/^([0-9]+)x[0-9]+/\1/' <<<"$RESOLUTION") CAMHEIGHT=$(sed -r 's/^[0-9]+x([0-9]+)/\1/' <<<"$RESOLUTION") echo "DEVICE=$CAMDEVICE" >> /etc/$OUTFILE.env echo "RES=$RESOLUTION" >> /etc/$OUTFILE.env echo "FRAMERATE=$FRAMERATE" >> /etc/$OUTFILE.env echo "PORT=$CAMPORT" >> /etc/$OUTFILE.env echo "WIDTH=$CAMWIDTH" >> /etc/$OUTFILE.env echo "HEIGHT=$CAMHEIGHT" >> /etc/$OUTFILE.env cp $SCRIPTDIR/$OUTFILE.service /etc/systemd/system/ echo "camera:cam${INUM}_$INSTANCE port:$CAMPORT udev:true" >> /etc/octoprint_cameras #config.yaml modifications - only if INUM not set if [ -z "$INUM" ]; then docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set plugins.classicwebcam.snapshot "http://localhost:$CAMPORT?action=snapshot" if [ -z "$CAMHAPROXY" ]; then docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set plugins.classicwebcam.stream "http://$(hostname).local:$CAMPORT?action=stream" else docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config set plugins.classicwebcam.stream "/cam_$INSTANCE/?action=stream" fi docker exec -it $INSTANCE $OCTOEXEC --basedir $BASE config append_value --json system.actions "{\"action\": \"Reset video streamer\", \"command\": \"sudo systemctl restart cam_$INSTANCE\", \"name\": \"Restart webcam\"}" if prompt_confirm "Instance must be restarted for settings to take effect. Restart now?"; then systemctl restart $INSTANCE fi fi write_cam_udev if [ -n "$CAMHAPROXY" ]; then HAversion=$(haproxy -v | sed -n 's/^.*version \([0-9]\).*/\1/p') #find frontend line, do insert sed -i "/use_backend $INSTANCE if/a\ use_backend cam${INUM}_$INSTANCE if { path_beg /cam${INUM}_$INSTANCE/ }" /etc/haproxy/haproxy.cfg if [ $HAversion -gt 1 ]; then EXTRACAM="backend cam${INUM}_$INSTANCE\n\ http-request replace-path /cam${INUM}_$INSTANCE/(.*) /|\1\n\ server webcam1 127.0.0.1:$CAMPORT" else EXTRACAM="backend cam${INUM}_$INSTANCE\n\ reqrep ^([^|\ :]*)|\ /cam${INUM}_$INSTANCE/(.*) |\1|\ /|\2 \n\ server webcam1 127.0.0.1:$CAMPORT" fi echo "#cam${INUM}_$INSTANCE start" >> /etc/haproxy/haproxy.cfg sed -i "/#cam${INUM}_$INSTANCE start/a $EXTRACAM" /etc/haproxy/haproxy.cfg #these are necessary because sed append seems to have issues with escaping for the /\1 sed -i 's/\/|1/\/\\1/' /etc/haproxy/haproxy.cfg sed -i 's/\/|2/\/\\2/' /etc/haproxy/haproxy.cfg #haproxy 1.x correction sed -i 's/|/\\/g' /etc/haproxy/haproxy.cfg echo "#cam${INUM}_$INSTANCE stop" >> /etc/haproxy/haproxy.cfg systemctl restart haproxy fi } write_cam_udev() { #Either Serial number or USB port #Serial Number if [ -n "$CAM" ]; then echo SUBSYSTEM==\"video4linux\", ATTRS{serial}==\"$CAM\", ATTR{index}==\"0\", SYMLINK+=\"cam${INUM}_$INSTANCE\" >> /etc/udev/rules.d/99-octoprint.rules fi #USB port camera if [ -n "$USBCAM" ]; then echo SUBSYSTEM==\"video4linux\",KERNELS==\"$USBCAM\", SUBSYSTEMS==\"usb\", ATTR{index}==\"0\", DRIVERS==\"uvcvideo\", SYMLINK+=\"cam${INUM}_$INSTANCE\" >> /etc/udev/rules.d/99-octoprint.rules fi } add_camera() { PI=$1 INUM='' CAMHAPROX='' get_settings if [ "$STREAMER" == none ]; then echo "No camera streamer service has been installed." echo "Use the utilities menu to add one." main_menu fi if [ $SUDO_USER ]; then user=$SUDO_USER; fi echo 'Adding camera' | log if [ -z "$INSTANCE" ]; then PS3='Select instance number to add camera to: ' get_instances true select camopt in "${INSTANCE_ARR[@]}" do if [ "$camopt" == Quit ]; then main_menu fi echo "Selected instance for camera: ${cyan}$camopt${white}" INSTANCE=$camopt OCTOCONFIG="/opt/octoprint/" BASE="/opt/octoprint/$INSTANCE" if grep -q "cam_$INSTANCE" /etc/udev/rules.d/99-octoprint.rules; then echo "It appears this instance already has at least one camera." if prompt_confirm "Do you want to add an additional camera for this instance?"; then echo "Enter a number for this camera." echo "Ex. entering 2 will setup a service called cam2_$INSTANCE" echo read INUM if [ -z "$INUM" ]; then echo "No value given, setting as 2" INUM='2' fi else main_menu fi fi break done fi #for now just set a flag that we are going to write cameras behind haproxy if [ "$HAPROXY" == true ]; then if prompt_confirm "Add cameras to haproxy?"; then CAMHAPROXY=1 fi fi if [ -z "$PI" ]; then detect_camera if [ -n "$NOSERIAL" ] && [ -n "$CAM" ]; then unset CAM fi #Failed state. Nothing detected if [ -z "$CAM" ] && [ -z "$TEMPUSBCAM" ] && [ -z "$BYIDCAM" ]; then echo echo "${red}No camera was detected during the detection period.${white}" echo "Try again or try a different camera." return fi #only BYIDCAM if [ -z "$CAM" ] && [ -z "$TEMPUSBCAM" ] && [ -n "$BYIDCAM" ]; then echo "Camera was only detected as ${cyan}/dev/v4l/by-id${white} entry." echo "This will be used as the camera device identifier" fi #only USB address if [ -z "$CAM" ] && [ -n "$TEMPUSBCAM" ]; then echo "${red}Camera Serial Number not detected${white}" echo -e "Camera will be setup with physical USB address of ${cyan}$TEMPUSBCAM.${white}" echo "The camera will have to stay plugged into this location." USBCAM=$TEMPUSBCAM fi #serial number if [ -n "$CAM" ]; then echo -e "Camera detected with serial number: ${cyan}$CAM ${white}" check_sn "$CAM" fi else echo echo echo "Setting up a Pi camera service." echo "Please note that mixing this setup with USB cameras may lead to issues." echo "Don't expect extensive support for trying to fix these issues." echo echo fi CAMPORT=$(tail -1 /etc/octoprint_cameras 2>/dev/null | sed -n -e 's/^.*port:\([[:graph:]]*\) \(.*\)/\1/p') if [ -z "$CAMPORT" ]; then CAMPORT=8000 fi CAMPORT=$((CAMPORT+1)) echo "Settings can be modified after initial setup in /etc/systemd/system/cam${INUM}_$INSTANCE.service" echo while true; do echo "Camera Resolution [default: 640x480]:" read RESOLUTION if [ -z $RESOLUTION ] then RESOLUTION="640x480" break elif [[ $RESOLUTION =~ ^[0-9]+x[0-9]+$ ]] then break fi echo "Invalid resolution" done echo "Selected camera resolution: $RESOLUTION" | log echo "Camera Framerate (use 0 for ustreamer hardware) [default: 5]:" read FRAMERATE if [ -z "$FRAMERATE" ]; then FRAMERATE=5 fi echo "Selected camera framerate: $FRAMERATE" | log #Need to check if this is a one-off install if [ -n "$camopt" ]; then write_camera #Pi Cam setup, replace cam_INSTANCE with /dev/video0 if [ -n "$PI" ] && [ "$STREAMER" == ustreamer ]; then echo SUBSYSTEM==\"video4linux\", ATTRS{name}==\"video0\", SYMLINK+=\"cam${INUM}_$INSTANCE\" >> /etc/udev/rules.d/99-octoprint.rule fi systemctl start cam${INUM}_$INSTANCE.service systemctl enable cam${INUM}_$INSTANCE.service systemctl daemon-reload udevadm control --reload-rules udevadm trigger main_menu fi }