Initial commit
This commit is contained in:
parent
15d8d45d27
commit
c84da24975
|
@ -0,0 +1,94 @@
|
||||||
|
|
||||||
|
FROM python:2.7
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y cmake libjpeg62-turbo-dev g++ wget unzip psmisc
|
||||||
|
|
||||||
|
RUN cd /tmp/ && \
|
||||||
|
wget https://github.com/jacksonliam/mjpg-streamer/archive/master.zip && \
|
||||||
|
unzip master
|
||||||
|
|
||||||
|
RUN cd /tmp/mjpg-streamer-master/mjpg-streamer-experimental/ && \
|
||||||
|
make && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
ENV CURA_VERSION=15.04.6
|
||||||
|
ARG tag=master
|
||||||
|
|
||||||
|
WORKDIR /opt/octoprint
|
||||||
|
|
||||||
|
#install ffmpeg
|
||||||
|
RUN cd /tmp \
|
||||||
|
&& wget -O ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-32bit-static.tar.xz \
|
||||||
|
&& mkdir -p /opt/ffmpeg \
|
||||||
|
&& tar xvf ffmpeg.tar.xz -C /opt/ffmpeg --strip-components=1 \
|
||||||
|
&& rm -Rf /tmp/*
|
||||||
|
|
||||||
|
#install Cura
|
||||||
|
RUN cd /tmp \
|
||||||
|
&& wget https://github.com/Ultimaker/CuraEngine/archive/${CURA_VERSION}.tar.gz \
|
||||||
|
&& tar -zxf ${CURA_VERSION}.tar.gz \
|
||||||
|
&& cd CuraEngine-${CURA_VERSION} \
|
||||||
|
&& mkdir build \
|
||||||
|
&& make \
|
||||||
|
&& mv -f ./build /opt/cura/ \
|
||||||
|
&& rm -Rf /tmp/*
|
||||||
|
|
||||||
|
#Create an octoprint user
|
||||||
|
RUN useradd -ms /bin/bash octoprint && adduser octoprint dialout
|
||||||
|
RUN chown octoprint:octoprint /opt/octoprint
|
||||||
|
USER octoprint
|
||||||
|
|
||||||
|
#This fixes issues with the volume command setting wrong permissions
|
||||||
|
RUN mkdir /home/octoprint/.octoprint
|
||||||
|
|
||||||
|
#Install Octoprint
|
||||||
|
RUN git clone --branch $tag https://github.com/foosel/OctoPrint.git /opt/octoprint \
|
||||||
|
&& virtualenv venv \
|
||||||
|
&& ./venv/bin/python setup.py install \
|
||||||
|
&& echo 2
|
||||||
|
|
||||||
|
RUN /opt/octoprint/venv/bin/python -m pip install https://github.com/FormerLurker/Octolapse/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/pablogventura/Octoprint-ETA/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/1r0b1n0/OctoPrint-Tempsgraph/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/dattas/OctoPrint-DetailedProgress/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/kennethjiang/OctoPrint-Slicer/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/marian42/octoprint-preheat/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/jneilliii/OctoPrint-TasmotaMQTT/archive/0.3.0.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/mikedmor/OctoPrint_MultiCam/archive/master.zip
|
||||||
|
|
||||||
|
# Installing from sillyfrog until the PR is merged to master
|
||||||
|
RUN /opt/octoprint/venv/bin/python -m pip install https://github.com/sillyfrog/Octoslacka/archive/master.zip && \
|
||||||
|
/opt/octoprint/venv/bin/python -m pip install https://github.com/sillyfrog/OctoPrint-MQTT/archive/devel.zip
|
||||||
|
|
||||||
|
VOLUME /home/octoprint/.octoprint
|
||||||
|
|
||||||
|
|
||||||
|
### Klipper setup ###
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN apt-get install -y sudo
|
||||||
|
|
||||||
|
COPY klippy.sudoers /etc/sudoers.d/klippy
|
||||||
|
|
||||||
|
RUN useradd -ms /bin/bash klippy
|
||||||
|
|
||||||
|
USER octoprint
|
||||||
|
|
||||||
|
WORKDIR /home/octoprint
|
||||||
|
|
||||||
|
RUN git clone https://github.com/KevinOConnor/klipper
|
||||||
|
|
||||||
|
RUN ./klipper/scripts/install-octopi.sh
|
||||||
|
|
||||||
|
RUN cp klipper/config/printer-anet-a8-2017.cfg /home/octoprint/printer.cfg
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
COPY start.py /
|
||||||
|
|
||||||
|
CMD ["/start.py"]
|
31
README.md
31
README.md
|
@ -1,2 +1,31 @@
|
||||||
# OctoPrint-Klipper-mjpg-Dockerfile
|
# OctoPrint-Klipper-mjpg-Dockerfile
|
||||||
A Dockerfile for running OctoPrint Klipper and mjpg in a single container
|
A Dockerfile for running OctoPrint Klipper and mjpg in a single container.
|
||||||
|
|
||||||
|
My initial goal was to run these across different containers, but I couldn't get the Docker permissions to play nicely.
|
||||||
|
|
||||||
|
This is very much written for what I needed, so you'll likely need to hack this up for your setup. I've been using it for a little while now and it's going well.
|
||||||
|
|
||||||
|
Also included are some udev rules for reference that I use. These will need to be updated with your API key etc, however it makes connecting/disconnecting (power on/off) of the printer much less painful.
|
||||||
|
|
||||||
|
## Running the container
|
||||||
|
|
||||||
|
Once the container is built (the usual `docker build . -t okmd`), I use the following command to run it (again, you will need to customise for your setup, I have 3 cameras also connected):
|
||||||
|
|
||||||
|
```
|
||||||
|
docker kill octoprint2
|
||||||
|
docker rm octoprint2
|
||||||
|
docker run --name octoprint2 -d -v /etc/localtime:/etc/localtime:ro -v /home/user/Documents/octoprint-config:/home/octoprint/.octoprint \
|
||||||
|
--device /dev/ttyUSB0:/dev/ttyUSB0 \
|
||||||
|
--device /dev/video0:/dev/video0 \
|
||||||
|
--device /dev/video1:/dev/video1 \
|
||||||
|
--device /dev/video2:/dev/video2 \
|
||||||
|
-p 5000:5000 -p 8080:8080 -p 8081:8081 -p 8082:8082\
|
||||||
|
-e "MJPG=input_uvc.so -r HD -d /dev/video2" \
|
||||||
|
-e "MJPG1=input_uvc.so -r HD -d /dev/video0" -e "MJPG_PORT1=8081" \
|
||||||
|
-e "MJPG2=input_uvc.so -r HD -d /dev/video1" -e "MJPG_PORT2=8082" \
|
||||||
|
okmd
|
||||||
|
```
|
||||||
|
|
||||||
|
Your Klipper `printer.cfg` should be kept in the OctoPrint config directory (this is where it looks for it at startup).
|
||||||
|
|
||||||
|
If you have any questions, feel free to log an issue on this project, and I'll see if I can help.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
octoprint ALL=(ALL:ALL) NOPASSWD: ALL
|
|
@ -0,0 +1,57 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
|
|
||||||
|
MJPG = [
|
||||||
|
"/usr/local/bin/mjpg_streamer",
|
||||||
|
"-i",
|
||||||
|
"%(input)s",
|
||||||
|
"-o",
|
||||||
|
"output_http.so -p %(port)s -w /usr/local/share/mjpg-streamer/www/",
|
||||||
|
]
|
||||||
|
|
||||||
|
MJPG_INPUT_DEFAULT = "input_uvc.so -r HD"
|
||||||
|
|
||||||
|
OCTOPRINT = ["/opt/octoprint/venv/bin/octoprint", "serve"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mjpg_processes = []
|
||||||
|
mjpg_ports = [5000] # Reserve the OctoPrint port
|
||||||
|
for k, v in os.environ.iteritems():
|
||||||
|
if k.startswith("MJPG") and not k.startswith("MJPG_"):
|
||||||
|
v = v.strip()
|
||||||
|
port_env = "MJPG_PORT" + k[4:]
|
||||||
|
port = int(os.environ.get(port_env, 8080))
|
||||||
|
if port in mjpg_ports:
|
||||||
|
raise ValueError("Port %s from key %s already in use" % (port, port_env))
|
||||||
|
if not v:
|
||||||
|
v = MJPG_INPUT_DEFAULT
|
||||||
|
subs = {'input': v, 'port': port}
|
||||||
|
cmd = []
|
||||||
|
for part in MJPG:
|
||||||
|
cmd.append(part % subs)
|
||||||
|
print("Starting: %s" % (cmd,))
|
||||||
|
mjpg_processes.append(subprocess.Popen(cmd))
|
||||||
|
|
||||||
|
# Start klipper
|
||||||
|
klipper = subprocess.Popen(['sudo', '-u', 'octoprint', '/home/octoprint/klippy-env/bin/python', '/home/octoprint/klipper/klippy/klippy.py', '/home/octoprint/.octoprint/printer.cfg'])
|
||||||
|
|
||||||
|
os.setgid(
|
||||||
|
1000
|
||||||
|
) # Drop privileges, https://stackoverflow.com/questions/2699907/dropping-root-permissions-in-python#2699996
|
||||||
|
os.setuid(1000)
|
||||||
|
os.environ['HOME'] = '/home/octoprint'
|
||||||
|
# subprocess.Popen('env', shell=True).wait()
|
||||||
|
while 1:
|
||||||
|
Poctoprint = subprocess.Popen(OCTOPRINT)
|
||||||
|
Poctoprint.wait()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# udev Rules and Commands
|
||||||
|
|
||||||
|
This directory contains the commands and rules I add to udev to make turning the printer on and off go smoothly, including re-connecting (my Docker container runs 24x7, however I turn off the printer when not in use).
|
||||||
|
|
||||||
|
The `okmd-udev.rules` file should be copied to `/etc/udev/rules.d/`, and updated to have the correct paths and device names for your environment.
|
||||||
|
|
||||||
|
The commands (`printer-*`), should also be updated to match your device names, and include your OctoPrint API key.
|
|
@ -0,0 +1,2 @@
|
||||||
|
ACTION=="add", KERNEL=="ttyUSB*", SUBSYSTEM=="tty", RUN+="/somewhere/printer-connected"
|
||||||
|
ACTION=="remove", KERNEL=="ttyUSB*", SUBSYSTEM=="tty", RUN+="/somewhere/printer-disconnected"
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
logf = open('/var/tmp/printer-connected.log', 'a')
|
||||||
|
|
||||||
|
DEVNAME = os.environ['DEVNAME']
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
logf.write('%s\n' % (msg,))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
log(time.asctime())
|
||||||
|
log(DEVNAME)
|
||||||
|
os.system('chmod a+wr %s' % (DEVNAME,))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
|
logf = open('/var/tmp/printer-connected.log', 'a')
|
||||||
|
|
||||||
|
DEVNAME = os.environ['DEVNAME']
|
||||||
|
|
||||||
|
RESTART_STATES = [
|
||||||
|
'Offline',
|
||||||
|
'Cancelling',
|
||||||
|
'Operational',
|
||||||
|
]
|
||||||
|
|
||||||
|
OCTOPRINT_URL = 'http://localhost:5000/'
|
||||||
|
API_KEY = 'XXX'
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
logf.write('%s\n' % (msg,))
|
||||||
|
|
||||||
|
def currentstate():
|
||||||
|
headers = {'X-Api-Key': API_KEY}
|
||||||
|
url = OCTOPRINT_URL + '/api/job'
|
||||||
|
r = requests.get(url, headers=headers)
|
||||||
|
return r.json()['state']
|
||||||
|
|
||||||
|
def main():
|
||||||
|
log(time.asctime())
|
||||||
|
log("Disconnecting: {}".format(DEVNAME))
|
||||||
|
|
||||||
|
state = currentstate()
|
||||||
|
if state not in RESTART_STATES and DEVNAME != '/dev/ttyUSB0':
|
||||||
|
log("Not restarting. State: {} DEVNAME: {}".format(state, DEVNAME))
|
||||||
|
# Don't reset the firmware if not in a known safe state
|
||||||
|
return
|
||||||
|
|
||||||
|
headers = {'X-Api-Key': API_KEY}
|
||||||
|
json = {
|
||||||
|
"command": "FIRMWARE_RESTART",
|
||||||
|
}
|
||||||
|
|
||||||
|
url = OCTOPRINT_URL + '/api/printer/command'
|
||||||
|
r = requests.post(
|
||||||
|
url,
|
||||||
|
json=json,
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
|
||||||
|
if (r.status_code == 204):
|
||||||
|
log("Disconnected OK")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
log("Error disconnecting: %s" % (r,))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue