What is the problem?
I'm having trouble setting up a webcam with a docker install of Octoprint.
I'm guessing the mpeg streamer is not part of the default docker install and I'm guessing I need to add this manually. I was hoping someone could point me in the right direction (or even better update the offical docker repository to include webcam setup/) of the correct modifications to the dockerfile & docker-compose.yaml
Background
I previously had Octopi / Octoprint working nicely with a raspberryPi & a PS2 eye USB webcam.
I'm in the process of consolidating several devices within docker containers.
What did you already try to solve it?
- I've check out the /wiki/Webcams-known-to-work for information but no docker specific guidance
- I believe i have allowed (refer docker-compose.ymal below) the dev/video0 device through to the docker container (and I don't think i have a permissions problem)
Additional information about your setup
Octoprint looks to be working successfully
Docker: hub.docker.com/r/octoprint/octoprint/
Printer: Mendel Max 3
docker-compose.ymal
'''
version: '2'
services:
octoprint:
build: .
image: octoprint/octoprint
container_name: octoprint
ports:
- 5000:5000
devices:
- /dev/ttyACM0:/dev/ttyACM0
- /dev/video0:/dev/video0
volumes:
- ./config:/home/octoprint/.octoprint
restart: always
'''
My current theory is that being a USB webcam, it needs to be allowed through from the host machine to the container in the docker-compose.yaml and that
devices:
-/dev/video0:/dev/video0
doesn't sufficiently allow the USB port in use through to the container.
But I'm still having trouble identifying exactly what USB port it is connected to (?)
I can Identify the device and get its details with lsusb -vvv
or I can get a list of tty ports ls /dev | grep tty
(this shows a long list of tty ports but no clearly identification of the webcam)
tty
tty0
tty1
tty10
tty11
tty12
tty13
tty14
tty15
tty16
tty17
tty18
tty19
tty2
tty20
tty21
tty22
tty23
tty24
tty25
tty26
tty27
tty28
tty29
tty3
tty30
tty31
tty32
tty33
tty34
tty35
tty36
tty37
tty38
tty39
tty4
tty40
tty41
tty42
tty43
tty44
tty45
tty46
tty47
tty48
tty49
tty5
tty50
tty51
tty52
tty53
tty54
tty55
tty56
tty57
tty58
tty59
tty6
tty60
tty61
tty62
tty63
tty7
tty8
tty9
ttyACM0
ttyprintk
ttyS0
ttyS1
ttyS10
ttyS11
ttyS12
ttyS13
ttyS14
ttyS15
ttyS16
ttyS17
ttyS18
ttyS19
ttyS2
ttyS20
ttyS21
ttyS22
ttyS23
ttyS24
ttyS25
ttyS26
ttyS27
ttyS28
ttyS29
ttyS3
ttyS30
ttyS31
ttyS4
ttyS5
ttyS6
ttyS7
ttyS8
ttyS9
But it is still unclear (to me at least) exactly which tty USB port has the webcam connected.
Any help, hits and tips would be greatly appreciated.
lsusb -vvv
Bus 001 Device 003: ID 1415:2000 Nam Tai E&E Products Ltd. or OmniVision Technologies, Inc. Sony Playstation Eye
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x1415 Nam Tai E&E Products Ltd. or OmniVision Technologies, Inc.
idProduct 0x2000 Sony Playstation Eye
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 142
bNumInterfaces 3
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 10
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 1 Control Device
bInterfaceProtocol 0
iInterface 0
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdADC 1.00
wTotalLength 42
bInCollection 1
baInterfaceNr( 0) 2
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0201 Microphone
bAssocTerminal 2
bNrChannels 4
wChannelConfig 0x0000
iChannelNames 0
iTerminal 0
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 2
wTerminalType 0x0101 USB Streaming
bAssocTerminal 1
bSourceID 3
iTerminal 0
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 3
bSourceID 1
bControlSize 1
bmaControls( 0) 0x00
bmaControls( 1) 0x02
Volume Control
bmaControls( 2) 0x02
Volume Control
bmaControls( 3) 0x02
Volume Control
bmaControls( 4) 0x02
Volume Control
iFeature 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
AudioStreaming Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 2
bDelay 1 frames
wFormatTag 1 PCM
AudioStreaming Interface Descriptor:
bLength 11
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bNrChannels 4
bSubframeSize 2
bBitResolution 16
bSamFreqType 1 Discrete
tSamFreq[ 0] 16000
Endpoint Descriptor:
bLength 9
bDescriptorType 5
bEndpointAddress 0x84 EP 4 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0300 1x 768 bytes
bInterval 4
bRefresh 0
bSynchAddress 0
AudioControl Endpoint Descriptor:
bLength 7
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x01
Sampling Frequency
bLockDelayUnits 0 Undefined
wLockDelay 0 Undefined
It's possible if not even likely that the device endpoint doesn't include "tty" in it. It could start with "usb" or have that somewhere in the name. Or maybe it doesn't.
ls -l /dev
I will say that there is often a lookup created dynamically in cases like this and it can be useful in finding your device once it's been plugged in.
cd /dev
find . -name by-id
Once you find a subdirectory like this (especially under the appropriate folder like "video" or similar device category), then cd
into this folder and do an ls -l
again. You should see the individual IDs as presented earlier in that lsusb
command. I was doing some development with RFID readers and barcode scanners and this technique comes in handy. Once you get to the symlink in question, it should indicate the actual path to the device that was created.
Also, dmesg
can sometimes reveal what this is.
Thanks for the pointers.
I'm a little out of my depth with the whole tty & dev naming area but as far as I can tell...
My printer is coming through on /dev/ttyACM0
and the camera is /dev/video0
as such i added these to the docker-compose.yaml but I was suspicion that I may also need to add something more than /dev/video0
.
I may need to allow another port through to the host machine, after a lot of googling, looks like the mpeg-streamer may use a different port (?). I'm guessing this would be part of the choice in the setup of the container. I've played with adding the following but still no success thus far.
port:
- 8089:8080
- 8088:8088
I did find a nasty hack in the form of streaming the camera from the host machine (refer https://gist.github.com/endolith/2052778) but it really goes against the whole docker containerisation concept. This at least showed the camera was working and could be streamed to a port, but its no real long term solution.
A standard command line without the webcam might look like:
docker run -d -v --device /dev/ttyACM0:/dev/ttyACM0 -p 5000:5000 --name octoprint octoprint/octoprint
So I'm guessing that you'd have to double up in those --device
and -p
sections for the video, right?
docker run -d -v --device /dev/ttyACM0:/dev/ttyACM0 --device /dev/video0:/dev/video0 -p 5000:5000 -p 8080:8080 --name octoprint octoprint/octoprint
mmm... lets see if I can clarify. (Sorry if I'm stating the obvious here)
I'm running my docker instance using docker-compose
rather than a docker run <image>
(If you haven't used it, at its most basic level this is a nice tool to spool up docker containers with the parameters stored in a text file docker-compose.ymal
which can then quickly launch containers via a single command docker-compose up -d
)
...but in essentially it should do the same thing as run.
So i think the answer to your question is yes, I'm trying to allow several things through from the Host to the container:
Devices:
- /dev/ttyACM0 #USB connection to Printer
- /dev/video0 #PS3 eye webcam
Ports:
- 5000 #Octoprint container
- 8080 #This was for testing I suspected this was the port the mpeg-streamer was using
- 8088 #This was for testing I suspected this was the port the mpeg-streamer was using
version: '2'
services:
octoprint:
build: .
image: octoprint/octoprint
container_name: octoprint
ports:
- 5000:5000
- 8080:8080
- 8088:8088
devices:
- /dev/ttyACM0:/dev/ttyACM0
- /dev/video0:/dev/video0
volumes:
- ./config:/home/octoprint/.octoprint
- /dev/ttyACM0:/dev/ttyACM0
restart: always
So... more looking... no more answers yet.
I drilled into the dockerfile
(see below) and it looks like there is only one port exposed port 5000
I also can't obviously see where the jpeg-streamer is added to the dockerfile
not sure if I'm just over looking something obvious or its not included in the Image and needs adding / exposing separately.
The single exposed port makes me think that it is not possible to access the webcam stream on any other port via the http://<hostIP>:<port>
(thus its pointless exposing other ports to the host in the docker-compose.ymal
) and the only option for the stream is the internal loop back on 127.0.0.1
(assuming that the streamer is installed at all)
Any thoughts or ideas are welcome?
FROM python:2.7
EXPOSE 5000
LABEL maintainer "gaetancollaud@gmail.com"
ENV CURA_VERSION=15.04.6
ARG tag=master
WORKDIR /opt/octoprint
# In case of alpine
#RUN apk update && apk upgrade \
# && apk add --no-cache bash git openssh gcc\
# && pip install virtualenv \
# && rm -rf /var/cache/apk/*
#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
VOLUME /home/octoprint/.octoprint
CMD ["/opt/octoprint/venv/bin/octoprint", "serve"]
This probably works as expected but I've also seen foosel specify the port here in this invocation. But you're not complaining about OctoPrint just the webcam so I guess 5000 is the default.
Do you need to activate the virtual environment? Not that I've taken the approach that you're using but it's typical to call the source path/bin/activate
before doing the python setup.py install
command.
Not 100% clear what you are recommending trying here.
It my understanding that docker setups the image
with a dockerfile
("offical" octoprint/octoprint
dockerfile was included in the previous post) this builds the image & environment from which the active docker container
is generated from.
From what I can tell the serve
command is just launching the octoprint webserver/ webpage via ip http://0.0.0.0:5000 within the container this is then shared to the host environment via the EXPOSE 5000
command.
I'm not really have any problem with octoprint living on port 5000.
I have found another "unofficial" docker image https://hub.docker.com/r/atwoz/octoprint/ that looks like it maybe a promising guide whilst I haven't had the time to test anything yet looks to contain a number of added components in its dockerfile
: (see below & compare to the previous posted dockerfile)
Notably installing mjpg-streamer and exposing port 8088. I suspect these maybe the parts "missing" (or deliberately left out) of the offical docker octoprint image.
Note: There maybe some very deliberate reasons for leaving these parts out of the image, I'm just not clear on what that would be. Possible the theory is the mjpg-streamer should live in an independent container and be "linked" to the octoprint container, given it was developed by a third party to octoprint
I would love to hear any reasoning on the exclusion / inclusion of these components and if possible the recommended strategy for including webcams with the offical docker version.
I suspect I'm not the first to have this problem and maybe not the last
FROM pypy:2-slim
MAINTAINER Ohad Galor Kimchi <ohadgk@gmail.com>
ENV OCTOPRINT_VERSION=1.2.15
ENV CURA_ENGINE_VERSION=15.04.6
RUN set -xe \
&& echo "Setup Temporary packages for compilation" \
&& export PKGS='build-essential subversion libjpeg-dev zlib1g-dev libv4l-dev wget unzip git' \
&& echo "Installing Dependencies" \
&& apt-get update \
&& apt-get install -y libprotobuf9 libav-tools avrdude libjpeg62-turbo curl imagemagick psmisc --no-install-recommends \
&& apt-get install -y ${PKGS} --no-install-recommends \
&& echo "Download OctoPrint/CuraEngine/mjpg-streamer" \
&& cd /tmp/ \
&& wget https://github.com/foosel/OctoPrint/archive/${OCTOPRINT_VERSION}.tar.gz \
&& wget https://github.com/Ultimaker/CuraEngine/archive/${CURA_ENGINE_VERSION}.tar.gz \
&& wget http://sourceforge.net/code-snapshots/svn/m/mj/mjpg-streamer/code/mjpg-streamer-code-182.zip \
&& echo "Installing mjpg-streamer" \
&& unzip mjpg-streamer-code-182.zip \
&& cd mjpg-streamer-code-182/mjpg-streamer \
&& make \
&& make install \
&& cd ../.. \
&& echo "Installing CuraEngine" \
&& tar -zxf ${CURA_ENGINE_VERSION}.tar.gz \
&& cd CuraEngine-${CURA_ENGINE_VERSION} \
&& mkdir build \
&& make \
&& mv -f ./build /CuraEngine/ \
&& cd .. \
&& echo "Installing OctoPrint" \
&& tar -zxf ${OCTOPRINT_VERSION}.tar.gz \
&& mv -f OctoPrint-${OCTOPRINT_VERSION} /octoprint/ \
&& cd /octoprint/ \
&& echo "Install OctoPrint requirements" \
&& pip install -r requirements.txt \
&& pip install pillow \
&& pypy setup.py install \
&& echo "Cleaning Temporary Packages + Installation leftovers" \
&& apt-get purge -y --auto-remove ${PKGS} \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /tmp/* /var/tmp/*
VOLUME /data
WORKDIR /data
EXPOSE 5000
# TODO: Until i'll add HAProxy
EXPOSE 8088
ADD octoprint.sh /usr/bin/
ENV YUV_CAMERA "true"
ENTRYPOINT ["octoprint.sh"]
CMD []
Regarding "why" the exclusion, I'd suggest that someone was pretty happy that they got this to work under Docker and called it a success. If/when they remembered the webcam, they probably got a headache and rationalized that it was good enough. There's some sort of "rest inertia" in these situations, as a would-be author: "should I add support for the webcam?", "if I add support for the webcam, don't I also have to do USB-based webcams and ribbon-based...?"
Guy was just indicating to me in another thread that he's just added Docker support to the official OctoPi image he maintains. He's asked me to test it on OSX so I may do this later this week. Actually, I think he indicated that he did this work with CustomPiOS, the underlying platform that he uses for OctoPi.
In this version you've provided, I don't see any of the virtualenv stuff but perhaps this is how Docker just does it.
I can certainly empathise with Theory that the basic version works so that's a nice point to stop and take a break, maybe play with another issue. I have become a fan of containerisation but understandably its not for everyone, the octoPi image is a really great way to get up and running quickly also.
Not sure about virtualenv I really haven't played with it, but the beauty of docker & containerisation is the ability to hold an image with specific dependancies eg the specific python version required. I suspect this is removes the need for virtualenv. (I'm sure someone more knowledgeable can correct me if I'm wrong)
virtualenv
is a tool to create isolated Python environments.
I would prefer to remain on the main offical image if possible. I may need to delve into the docker documentation on the best / nicest way to add the jpeg-streamer to an offical image. (I suspect that just hacking in / cloning for the other version the missing jpeg-streamer lines to the existing dockerfile
is considered bad form, from an update & version control perspective)
I'll have a play when I get a clear afternoon and post back any lessons here.
That's my take on it, too: the containerization of Docker is the same sort of compartmentalization that virtualenv hopes to achieve. So why the need for two layers of compartmentalization? It makes no sense but I still see some of these examples/attempts/tutorials going there.
So I'm agreeing with you, in other words. The atwoz link above (foregoing virtualenv) looks like the best approach, in my humble opinion.
basically, how do I connect my ps3 PlayStation eye to octoprint? I am using an rpi 3b+. If someone could give me detailed instrux to me (I am as big a noob as anyone can get about this topic), it would be appreciated very much. I am running octoprint latest stable release. will the eye also work with octoprint anywhere?
Hi,
I was looking also for a solution to use Octoprint Camera with dockers and I came upon this thread.
I don`t know if you found a solution, but if you didn't, this is what helped me:
I am using a Raspberry Pi 4, a Raspi-Cam and Prusa Mini.
With Portainer I added a Stack, named it "octoprint" and in the Web editor section I added the following:
version: '2.2'
volumes:
octoprint:
services:
octoprint_mini:
restart: unless-stopped
image: octoprint/octoprint
ports:
- 5000:80
devices:
- /dev/ttyACM0:/dev/ttyACM0
volumes:
- "your media"/octoprint:/home/octoprint
mjpg-streamer:
restart: unless-stopped
image: openhorizon/mjpg-streamer-pi3
command: ./mjpg_streamer -o "output_http.so -w ./www" -i "input_uvc.so -r 1280x720 -d /dev/video0 -f 30"
devices:
- /dev/video0:/dev/video0
ports:
- 5001:8080
After deploying the stack, I was able to access the web interface with:
http://"RPi ip":5000
and the video feed with:
http://"RPi ip":5001/?action=stream
You can also follow this tutorial if you don't want to use Portainer:
https://www.youtube.com/watch?v=LcA9o6OGfEg&ab_channel=Print%27NPlay
I hope this helps
Just to let you know, since this post was quite old, there is now an official OctoPrint docker installation method, that comes with mjpg_streamer too.
Both images are the same and even mantained by the same user. Somehow I used the command in "Without docker-compose" section, but it didn't work as I expected. That's why I started looking for other options.
For anybody who still have problem with configuration of PS3 Eye on Raspberry with Docker, your docker-compose.yml should have look like this:
services:
octoprint:
image: octoprint/octoprint
restart: unless-stopped
ports:
- 80:80
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
- /dev/video0:/dev/video0
volumes:
- octoprint:/octoprint
environment:
- ENABLE_MJPG_STREAMER=true
- MJPG_STREAMER_INPUT=-r 640x480 -f 10 -y
volumes:
octoprint:
Especialy this setting is crucial:
- MJPG_STREAMER_INPUT=-r 640x480 -f 10 -y
Found it here: USB webcams known to work with mjpg-streamer
1 Like
Thank you so much i spent all day trying to figure it out but this worked straight away. you a real one
1 Like