Skip to content

Instantly share code, notes, and snippets.

@saper-2
Last active April 20, 2022 14:28
Show Gist options
  • Save saper-2/c7442e8869737eaff158a49db6fcb3a4 to your computer and use it in GitHub Desktop.
Save saper-2/c7442e8869737eaff158a49db6fcb3a4 to your computer and use it in GitHub Desktop.
Preview monitor for Octoprint on Raspberry Pi and DSI screen

Pre-req.

  1. Raspberry Pi (2,3,4 ; 0 and 1 might be to weak... )
  2. Display - I used 5" DSI from BTT (BigTreeTech)
  3. Octoprint with mjpeg-streamer

Setup

  1. Burn latest RaspiOS (I used raspbian 11 bullseye 2022-04-04-raspios-bullseye-armhf-lite ) on SD,
  2. Create default user (pi) and enable ssh (fastes use headless method - need 2 files to drop on sd boot partition: userconf and ssh)
  3. Run raspi-config and enable kms driver (raspi-config will install some packages doing this): 8. -> A2. -> G2. , also set RaspiOS to console-autologin mode, don't reboot yet.
  4. Edit /boot/config.txt, find line with dtoverlay and vc4-kms... , change kms to fkms: dtoverlay=vc4-fkms-v3d - otherwise vlc won't work 😒 , now reboot,
  5. Update system, install vlc (I don't remember if anything else I installed...),
  6. Test if streaming works - replace <octoprint_mjpeg_streamer:8080> for your IP address and port:
cvlc --play-and-exit --quiet --vout=mmal_vout --mmal-display=dsi "http://<octoprint_mjpeg_streamer:8080>/?action=stream"

If you want output to HDMI you have to tinker with --mmal-display=dsi and change dsi to hdmi-1/hdmi-2.

  1. if works then create 2 scripts start-monitor.sh and upovl-octo.py , put them into home dir.

  2. Open start-monitor.sh setup mjpeg_streamer address, and eventually other options. If you want to use HDMI you'll need to adjust too --mmal-vout-window for your monitor resolution, it take argument in format: <window_width>x<window_height>+<left_pos>+<top_pos>.

  3. Open upovl-octo.py , set octoprint address (and port), and api_key (to find in octoprint in user preferences window).

  4. Run upovl-octo.py without any arguments, to see if it'll get info from octoprint.

  5. If everything works, then edit file /home/<your_user>/.bashrc , and add at end a new line with path to start-monitor.sh script.

  6. Test it by running start-monitor.sh you should see on display stream from octoprint and some information about hot end temperature, progress, time left, and/or status text. You can change color of the text on displayed stream by tweaking color=0xFFFF00 in line with cvlc . COlor must be in RGB in HEX notatnion.

  7. Reboot to see if it works.

#!/bin/bash
# Script used to start python script that grab info from octoprint and prepare it for vlc marquee filter, and start the vlc in endless loop.
# If script happens to be started via SSH then it'll exit (to not double instances of python/lvc)
# Author: saper_2 @ 2022-04-19
# Octoprint webcam streaming address
STREAM_HOST="<OCTOPRINT_MJPEG_STREAMER>:8080"
if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then
echo "SSH connectiong detected, not starting monitor script."
exit 0 # do nothing
fi
echo "Starting streaming..."
# overlay file for vlc with info to be shown on video on display
OVL_FILE=/tmp/ovl.txt
OCTO_SCRIPT=/home/pi/upovl-octo.py
#cvlc --play-and-exit --quiet --vout=mmal_vout --mmal-display=dsi --mmal-vout-window 800x480+0+0 --sub-filter='marq{file="/tmp/ovl.txt",x=700,color=0xFFFFFF,size=18}' "http://$STREAM_HOST/?action=stream"
touch $OVL_FILE
# start script as bg job
$OCTO_SCRIPT >/tmp/octo-script.log $OVL_FILE 2>&1 &
while true; do
killall -TERM vlc 2>/dev/null
sleep 2;
killall -TERM vlc 2>/dev/null
# you'll need to do some adjustments if you want on hdmi (mmal-display & mmal-vout-window)
# tweak color=0x?????? to your preferences (color in RGB in hex format)
cvlc --play-and-exit --quiet --vout=mmal_vout --mmal-display=dsi --mmal-vout-window 800x480+0+0 --sub-filter='marq{file="'$OVL_FILE'",x=700,y=5,color=0xFFFF00,size=20}' "http://$STREAM_HOST/?action=stream"
done;
#!/usr/bin/env python3
# Script connect to octoprint API and get job & printer status, then format it into text file so it can be displayed
# by vlc marquee plugin on video stream.
# Run script without any argument to test if it works (the "debug_mode" )
# By default script is called from start-monitor.sh with argument that is path to the overlay text file or vlc.
# Author: saper_2 @ 2022-04-20
import requests
import math
import time
import sys
import os.path
# some config
octohost="192.168.2.71:5000"
apikey="F2FE8D35D84F4EE3A6CDAB0DFBDF7105" # get it from your user preferences in octoprint
ovlfile="/tmp/ovl.txt"
#vlc on RPi and DSI screen , driver video: dtoverlay=vc4-fkms-v3d (otherwise vlc will'be bitching):
#vlc --key-quit q --vout=mmal_vout --mmal-display=dsi --mmal-vout-window 800x480+0+0 --sub-filter='marq{file="/tmp/ovl.txt",x=700,color=0xFFFFFF,size=18}' http://192.168.xxxxx:8080/?action=stream
debug_mode=0
off_states = ( "Offline", "Opening serial connection", "Detecting serial connection", "Connecting" )
op_states = ( "Operational", "Starting print from SD", "Starting to send file to SD", "Starting", "Cancelling", "Pausing", "Resuming" )
print_states = ( "Printing", "Printing from SD", "Sending file to SD", "Paused", "Finishing", "Transferring file to SD" )
err_states = ( "Error", "Offline after error" )
# convert time in secs to dict h:m:s
def get_time(secs):
h=int(math.floor(secs/3600))
secs=secs-(h*3600)
m=int(math.floor(secs/60))
secs=secs-(m*60)
return { 'h': h, 'm': m, 's': secs }
# check for file, if no file then switch to debug_mode
if (len(sys.argv) > 1):
fp=sys.argv[1]
if (os.path.isfile(fp)):
ovlfile=fp
else:
debug_mode=1
else:
debug_mode=1
print("Starting VLC info updater script...")
if (debug_mode):
print("Debug mode actived. No file will be written.\r\nUse Ctrl+Z or Ctrl+C to end script.")
#if (1):
try:
while True:
# get print job info
prog=0.0
tleft=get_time(0)
tempt0=0.0
tempbd=0.0
state=-1 #0=offline ,1=Operational, 2=Printing, 3=Error
pstas=""
url="http://{0}/api/job?apikey={1}".format(octohost,apikey)
try:
res=requests.get(url)
if (res.status_code == 200):
json=res.json()
pstas=json['state']
# check print status
if (pstas in off_states):
state=0
elif (pstas in op_states):
state=1
elif (pstas in print_states):
state=2
elif (pstas in err_states):
state=3
else:
state=0
#end:if:elif:else
try:
prog=float(json['progress']['completion'])
except:
prog=0.0
#end:try
#print("Progress: {0: 5.2f}%".format(json['progress']['completion']))
try:
tleft=get_time(int(json['progress']['printTimeLeft']))
except:
tleft=get_time(0)
#end:try
#print("Time left: {h:02}:{m:02}:{s:02}".format(**tleft))
#end:if
except Exception as err:
print(err)
#end:try
if (state in (1,2)):
# get printer status
url="http://{0}/api/printer?apikey={1}".format(octohost,apikey)
try:
res=requests.get(url)
if (res.status_code == 200):
json=res.json()
try:
tempt0=float(json['temperature']['tool0']['actual'])
except:
tempt0=0.0
#end:try
try:
tempbd=float(json['temperature']['bed']['actual'])
except:
tempbd=0.0
#end:try
#print("Temperature End1: {0: 5.1f}°C".format(temph1))
#print("Temperature Bed : {0: 5.1f}°C".format(tempbd))
#end:if
except Exception as err2:
print(err2)
#end:try
#end:if
# if state is other than 0-3
line="-.-"
if (state == 0): #offline
line="- Printer offline -"
elif (state == 1): #operational
states=pstas
ldata = { 't0': tempt0, 'hb': tempbd, 'sta':states }
line="{sta} : HE={t0: 5.1f}°C HB={hb: 5.1f}°C".format(**ldata)
elif (state == 2): #printing/etc
ldata = { 'h': tleft['h'], 'm': tleft['m'], 's': tleft['s'], 'p': prog, 't0': tempt0, 'hb': tempbd }
line="{p: 5.2f}% {h:02}:{m:02}:{s:02} HE={t0: 5.1f}°C HB={hb: 5.1f}°C".format(**ldata)
elif (state == 3): #error
states=pstas
ldata = { 't0': tempt0, 'hb': tempbd, 'sta':states }
line="!! - {sta} - !!".format(**ldata)
#end:if:elif
#debugging :)
if (debug_mode):
print(line)
else:
# save line to overlay text file
try:
fh=open(ovlfile,'w')
fh.write(line)
fh.close()
except:
pass
#end:try
#end:if:else
time.sleep(10)
#end:while
except Exception as e:
print(e)
#end:try
print("\r\nScript end.\r\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment