<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="https://publishpress.com/"
	>

<channel>
	<title>3D Printing Archives - Krystof.IO</title>
	<atom:link href="https://krystof.io/topics/3d-printing/feed/" rel="self" type="application/rss+xml" />
	<link>https://krystof.io/topics/3d-printing/</link>
	<description>Numerous hobbies, various ramblings.</description>
	<lastBuildDate>Sun, 28 May 2023 04:33:35 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.2.9</generator>

<image>
	<url>https://krystof.io/wp-content/uploads/2019/10/cropped-site-icon-low-32x32.jpg</url>
	<title>3D Printing Archives - Krystof.IO</title>
	<link>https://krystof.io/topics/3d-printing/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Octoprint with Multiple Printers on One Ubuntu Linux Mini-PC</title>
		<link>https://krystof.io/octoprint-with-multiple-printers-on-one-ubuntu-linux-mini-pc/</link>
					<comments>https://krystof.io/octoprint-with-multiple-printers-on-one-ubuntu-linux-mini-pc/#respond</comments>
		
		<dc:creator><![CDATA[Eric R. Krystof]]></dc:creator>
		<pubDate>Thu, 18 May 2023 13:14:36 +0000</pubDate>
				<category><![CDATA[3D Printing]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[3d Printing]]></category>
		<guid isPermaLink="false">https://krystof.io/?p=2289</guid>

					<description><![CDATA[<p>Using Docker to connect three instances of Octoprint to three 3D Printers, all on one Linux machine with webcams.</p>
<p>The post <a rel="nofollow" href="https://krystof.io/octoprint-with-multiple-printers-on-one-ubuntu-linux-mini-pc/">Octoprint with Multiple Printers on One Ubuntu Linux Mini-PC</a> appeared first on <a rel="nofollow" href="https://krystof.io">Krystof.IO</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;m a big fan of Octoprint, and in the past I used it on a couple of Raspberry Pi computers, one instance per Pi.  Those things are harder to come by these days, so as I try to get my 3d printers up and running again after a long hiatus in storage, I wanted to try to take one cheap Windows Mini-PC and see if I could install Linux on it and utilize Docker to have multiple Octoprint instances, one for each printer, all running on one PC.  Each 3D Printer will also have a webcam attached.  I also wanted to use an external Wifi Adapter as the built in adapter on the Mini-PC didn&#8217;t have as much power.  So those are the goals: </p>



<ul>
<li>One PC to handle three printers
<ul>
<li>One Octoprint instance per Printer</li>



<li>USB Powered Hub to expand available ports</li>
</ul>
</li>



<li>Each printer has a webcam</li>



<li>External WiFi Adapter (better than the internal)</li>



<li>Docker containerization for ease of setup / config</li>
</ul>



<p>This article serves as the general build and install log of that setup.    It covers the basic install of Ubuntu, Docker, Octoprint, and some USB UDEV rules so we can make sure the printers and webcams always run under the expected device names.</p>



<h2 class="wp-block-heading" id="h-wiring-connections">Wiring Connections</h2>



<p>The Mini-PC I have has two USB 3.0 and two USB 2.0 ports.  I&#8217;ve got to hook up three webcams, three printers, and an external WiFi adapter, so that&#8217;s already 7.  So I had one six port powered USB 3.0 hub, which I wanted to attach the 3D Printer related stuff to, use the other USB 3.0 port for the WiFi adapter, and then have the other two ports open as needed.  That was the goal at least, it didn&#8217;t work out that way, but close.  I had to remove one camera from the hub and use one of the USB 2.0 ports for it (perhaps I was maxing out the hub with video?).  Nevertheless, that at least left one port open for something else someday. It&#8217;s going to be a headless system for the most part.</p>



<h2 class="wp-block-heading">Mini-PC Linux Software and Config</h2>



<p>This was fairly straightforward for the install side. <a href="https://ubuntu.com/download" target="_blank" rel="noreferrer noopener">Downloaded</a> the latest Ubuntu <strong>server </strong>image (could have done desktop, but it&#8217;s a headless system), used <a href="https://etcher.balena.io" target="_blank" rel="noreferrer noopener">Balena Etcher</a> to pop it on an SD Card, then shoved that card right into the Windows Mini PC and started the install (wiping out everything).  Once that was done, I installed <a href="https://www.cyberciti.biz/faq/how-to-install-ssh-on-ubuntu-linux-using-apt-get/" target="_blank" rel="noreferrer noopener" class="broken_link">open ssh</a> (if it wasn&#8217;t installed as part of the initial OS install) so I can just use Putty to connect via my main PC for ease of copy/paste. </p>



<h3 class="wp-block-heading">WiFi Adapter Compile and Install</h3>



<p>More optional than anything, since this is an adapter that doesn&#8217;t have direct Linux support at this time.  It&#8217;s better than the internal one my PC had though, so I&#8217;ll be using it.  It&#8217;s the <a href="https://www.amazon.com/gp/product/B01MZD7Z76/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1" target="_blank" rel="noreferrer noopener nofollow">Alfa AC1900 WiFi Adapter</a> and it requires special but easy handling.</p>



<p>Copy of the documentation from their website: <a href="https://docs.alfa.com.tw/Support/Linux/RTL8814AU/" target="_blank" rel="noreferrer noopener nofollow">https://docs.alfa.com.tw/Support/Linux/RTL8814AU/</a></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
sudo apt update
sudo apt install git build-essential
git clone https://github.com/aircrack-ng/rtl8812au.git
cd rtl8812au
make
sudo make install
</pre></div>


<p>After that I did a recycle, still wired in.  I had to update my netplan config to take the new settings for the new adapter.</p>



<p>My internal adapter on the PC (that sucks), was named <code>wlp2s0</code>.  But I need the name of the new adapter, so to get that&#8230;</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
sudo lshw -C network
</pre></div>


<p>This gives me the output of network adapters, and I can see a new one beyond my default internal, which should be the adapter we just compiled drivers for:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
*-network DISABLED
       description: Wireless interface
       physical id: 8
       bus info: usb@1:3
       logical name: wlx00c0caaedc2d
       serial: .....
       capabilities: ethernet physical wireless
       configuration: broadcast=yes driver=rtl88XXau driverversion=5.15.0-72-generic multicast=yes wireless=unassociated

</pre></div>


<p>The logical name <code>wlx00c0caaedc2d</code> is what I&#8217;m interested in.  Now I&#8217;ll edit the netplan config to set both ethernet and wifi as optional interfaces and get the adapter ready to connect to my SSID.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
sudo vi /etc/netplan/00-installer-config.yaml
</pre></div>


<p>That may bring up some default networking stuff.  I pretty much replace it with these contents:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
network:
  ethernets:
    enp1s0:
      dhcp4: true
      optional: true
  wifis:
    #    wlp2s0:
    #  optional: true
    #  access-points:
    #    &lt;SSID&gt;:
    #      password: &lt;PASSWORD&gt;
    #  dhcp4: true
    wlx00c0caaedc2d:
      optional: true
      access-points:
        &lt;SSID&gt;:
          password: &lt;PASSWORD&gt;
      dhcp4: true
  version: 2

</pre></div>


<p>After that we apply the settings with <code>sudo netplan apply</code> and we&#8217;re off.  I can see the adapter light blinking.  I reboot with the network cable disconnected to make sure I can still connect via WiFi.</p>



<h3 class="wp-block-heading">USB and UDEV rules</h3>



<p>I want to set some UDEV rules so that we know exactly the USB ports our devices are being plugged into (included devices attached to the powered hub I bought), so that I can create aliases accordingly (i.e. I want to use <code>/dev/ttyPrinter1</code> and <code>/dev/videoPrinter1</code> and so on instead of assuming <code>/dev/video0</code> is always the first camera.)</p>



<p>To do this, I open up an SSH session and type:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
udevadm monitor
</pre></div>


<p>This will now spit large walls of text every time I plug something in or take something out of USB ports.  I plugin the hub, and figure out which ports I&#8217;m going to use for which printer.  The goal here is to grab the right &#8216;port identifier&#8217; and use UDEV rules to map that consistently to the right device name.  <strong>I will always plug the printers/cameras into the same USB ports</strong>.  So I used a simple video camera and went from port to port, copying down the key line that shows which identifier the system uses for the specific port I just plugged into.  You&#8217;ll see a bunch of lines, but look for the one that defines a video device like /dev/video0 and then look to the left of that line.  You&#8217;ll see text like this, which I copied down into a notepad session:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
...
/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.1/1-4.1.2/1-4.1.2:1.0/  (printer-2)
...
/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.1/1-4.1.1/1-4.1.1:1.0/  (video-printer2)
...
/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.4/1-4.4:1.0/  (printer1)
...
/devices/pci0000:00/0000:00:14.0/usb1/1-4/1-4.3/1-4.3:1.0/  (video-printer1)
</pre></div>


<p>As I move the camera from port to port I see which key identifiers change (see the 1-4.1.2:1.0 becomes 1-4.1.<strong>1</strong>:1.0, or 1-4.<strong>4</strong>:1.0 as I move down the line)</p>



<p>I use those identifiers to build the udev rules file.  I store mine in <code>/etc/udev/rules.d/01-krystof-usb.rules</code> so here are my contents (as root):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
SUBSYSTEM==&quot;tty&quot;, KERNELS==&quot;1-4.4:1.0&quot;, SYMLINK+=&quot;ttyPrinter1&quot;
SUBSYSTEM==&quot;tty&quot;, KERNELS==&quot;1-4.4:1.0&quot;, RUN+=&quot;/var/lib/docker/composers/octoprint/restart-octoprint.sh octoprint1&quot;
SUBSYSTEM==&quot;tty&quot;, KERNELS==&quot;1-4.1.2:1.0&quot;, SYMLINK+=&quot;ttyPrinter2&quot;
SUBSYSTEM==&quot;tty&quot;, KERNELS==&quot;1-4.1.2:1.0&quot;, RUN+=&quot;/var/lib/docker/composers/octoprint/restart-octoprint.sh octoprint2&quot;
SUBSYSTEM==&quot;tty&quot;, KERNELS==&quot;1-4.1.4:1.0&quot;, SYMLINK+=&quot;ttyPrinter3&quot;
SUBSYSTEM==&quot;tty&quot;, KERNELS==&quot;1-4.1.4:1.0&quot;, RUN+=&quot;/var/lib/docker/composers/octoprint/restart-octoprint.sh octoprint3&quot;
SUBSYSTEM==&quot;video4linux&quot;, KERNELS==&quot;1-4.3:1.0&quot;, ATTR{index}==&quot;0&quot;, SYMLINK+=&quot;videoPrinter1&quot;
SUBSYSTEM==&quot;video4linux&quot;, KERNELS==&quot;1-4.1.1:1.0&quot;, ATTR{index}==&quot;0&quot;, SYMLINK+=&quot;videoPrinter2&quot;
SUBSYSTEM==&quot;video4linux&quot;, KERNELS==&quot;1-8:1.0&quot;, ATTR{index}==&quot;0&quot;, SYMLINK+=&quot;videoPrinter3&quot;
</pre></div>


<p>The printers use subsystem TTY, and the videos use subsystem video4Linux.  The &#8220;KERNELS&#8221; argument is where I put those uniquely changing identifiers from watching <code>udevadm monitor</code> running, and the actions afterwards are what we want to do with that device when it&#8217;s plugged in.  For my case, I want to create a symbolic link under /dev/ for the printer.  (I could have named them towards the printer model, but some of my models are the same so I just went with printer1, printer2, etc.  &#8211; You could easily put A B C, BobsPrinter, DavesPrinter (even if Dave&#8217;s not here), etc.</p>



<p>You&#8217;ll notice the lines are duplicated for the printers and then there&#8217;s a RUN option.  That executes a script for docker later when the printers are plugged in.  It attempts to restart the docker instances of OctoPrint when the printer is disconnected and reconnected (sometimes it OctoPrint in a container can&#8217;t detect that very well, so we basically perform a restart).  That script looks like this if you want to use it (if you don&#8217;t, remove those lines)  &#8211; Obviously those scripts don&#8217;t exist yet but will after I set up docker.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
#!/bin/sh
sleep 10
docker stop $1
sleep 10
docker start $1
exit 0
</pre></div>


<p>To apply the UDEV rules, and make sure there aren&#8217;t any errors in the config:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
sudo udevadm control --reload-rules &amp;&amp; sudo udevadm trigger
</pre></div>


<p>You can see if it works by connecting one printer or video camera to the hub you wrote down your identifiers for and put into the rules.  If you plug in the right device to the right port, you should get a <code>/dev/ttyPrinter1</code>, or <code>/dev/videoPrinter1</code> device available:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
#Plugged the printer into USB port designated for printer 1:
erkrystof@pc-octoprint:/etc/udev/rules.d$ ls /dev/tty*Pr*
/dev/ttyPrinter1
#Unplugged the printer from USB port that I designated for printer 1 and put it in printer 2:
erkrystof@pc-octoprint:/etc/udev/rules.d$ ls /dev/tty*Pr*
/dev/ttyPrinter2
</pre></div>


<h2 class="wp-block-heading">Docker and the OctoPrint Containers</h2>



<p>Followed the standard docker install for Ubuntu:</p>



<p><a href="https://docs.docker.com/engine/install/ubuntu/" target="_blank" rel="noreferrer noopener">https://docs.docker.com/engine/install/ubuntu/</a></p>



<p>I also like to use Portainer, but that&#8217;s entirely optional for you (it&#8217;s a web admin interface for Docker containers)</p>



<p><a href="https://www.portainer.io/install" target="_blank" rel="noreferrer noopener">https://www.portainer.io/install</a></p>



<p>Once docker is installed, we need to create the docker-compose.yml file.  I like to put mine under <code>/var/lib/docker/composers/octoprint</code>.  (I created the directory as root).  I use the &#8216;official&#8217; <a href="https://hub.docker.com/r/octoprint/octoprint" target="_blank" rel="noreferrer noopener">OctoPrint image</a>, which I&#8217;ve had no issues with thus far in its current state.  Read that page over to better understand what is happening below.</p>



<p><code>sudo vi /var/lib/docker/composers/octoprint/docker-compose.yml</code></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
version: &quot;2.4&quot;

services:
  octoprint1:
    container_name: octoprint1
    image: octoprint/octoprint
    restart: unless-stopped
    ports:
      - &quot;8001:80&quot;
    devices:
      - /dev/ttyPrinter1:/dev/ttyUSB0
      - /dev/videoPrinter1:/dev/video0
    volumes:
      - ./octoprint1:/octoprint
    environment:
      - ENABLE_MJPG_STREAMER=true
      - MJPG_STREAMER_INPUT=-n -r 1280x720
  octoprint2:
    container_name: octoprint2
    image: octoprint/octoprint
    restart: unless-stopped
    ports:
      - &quot;8002:80&quot;
    devices:
      - /dev/ttyPrinter2:/dev/ttyUSB0
      - /dev/videoPrinter2:/dev/video0
    volumes:
      - ./octoprint2:/octoprint
    environment:
      - ENABLE_MJPG_STREAMER=true
      - MJPG_STREAMER_INPUT=-n -r 1280x720
  octoprint3:
    container_name: octoprint3
    image: octoprint/octoprint
    restart: unless-stopped
    ports:
      - &quot;8003:80&quot;
    devices:
      - /dev/ttyPrinter3:/dev/ttyUSB0
      - /dev/videoPrinter3:/dev/video0
    volumes:
      - ./octoprint3:/octoprint
    environment:
      - ENABLE_MJPG_STREAMER=true
      - MJPG_STREAMER_INPUT=-n -r 1280x720
</pre></div>


<p>Since I&#8217;ve got three printers, and three webcams, I have three entries.  Easy enough.</p>



<div data-padding="10" class="wp-block-simple-blocks-info-block" style="background-color:#000000;color:#ffffff;padding:10px"><div data-iconsize="20" data-iconspace="20" class="icon" style="margin-right:20px"><span class="dashicon dashicons dashicons-info"></span></div><div>Configuring multiple OctoPrint instances?  You can just do one and then create a backup and restore to the others and change just the differences.  Saves time on initial installs and installing the same plugins 3X.</div></div>



<p>So then we <em>could</em> run the compose command from that directory (as root):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
docker compose up -d
</pre></div>


<p>Now, if I do this without having the USB cameras and printers connected via USB, none of the instances will actually start.  Each OctoPrint instance expects a video camera and tty device now before it will start.  See how we map our well known aliases to /dev/ttyUSB0 and /dev/video0 for every single instance?  That allows us to create multiple OctoPrint installs, but utilize different USB devices.  The UDEV rules helped us map ports to well known aliases.</p>



<p>At this point, I hooked up the printers and video cameras to the Linux PC, recycled everything to make sure all was good there, <em>then I ran <code>docker compose up -d</code></em>.  After that, I was able to hit the web interface on each instance at http://pc-octoprint.lan:8001 through 8003.  (Your hostname may vary, that&#8217;s up to you).</p>



<p>Now underneath our composers directory we&#8217;ll have the three OctoPrint install directories designated under the volumes section.</p>



<p>Key notes on some settings in OctoPrint come from the <a href="https://hub.docker.com/r/octoprint/octoprint" target="_blank" rel="noreferrer noopener">OctoPrint Docker image</a> page:</p>



<h4 class="wp-block-heading">Webcam Setup in OctoPrint</h4>



<p>Use the following values in the webcam &amp; timelapse settings screen of the initial setup:</p>



<figure class="wp-block-table"><table><thead><tr><th>Setting</th><th>Value</th></tr></thead><tbody><tr><td>Stream URL</td><td><code>/webcam/?action=stream</code></td></tr><tr><td>Snapshot URL</td><td><code>http://localhost:8080/?action=snapshot</code></td></tr><tr><td>Path to FFMPEG</td><td><code>/usr/bin/ffmpeg</code></td></tr></tbody></table></figure>



<h4 class="wp-block-heading">Container Environment based configs</h4>



<p>There are configuration values that you pass using container&nbsp;<code>--environment</code>&nbsp;options. Listed below are the options and their defaults. These are implicit in example&nbsp;<a href="https://github.com/OctoPrint/octoprint-docker/tree/master/docker-compose.yml" target="_blank" rel="noreferrer noopener">docker-compose.yml</a>, and if you wish to change them, refer to the docker-compose docs on setting environment variables.</p>



<figure class="wp-block-table"><table><thead><tr><th>variable</th><th>default</th></tr></thead><tbody><tr><td><code>CAMERA_DEV</code></td><td><code>/dev/video0</code>&nbsp;(see&nbsp;<a href="https://hub.docker.com/r/octoprint/octoprint#devices_note" target="_blank" rel="noreferrer noopener">note</a>)</td></tr><tr><td><code>MJPG_STREAMER_INPUT</code></td><td><code>-y -n -r 640x480</code></td></tr><tr><td><code>ENABLE_MJPG_STREAMER</code></td><td><code>false</code></td></tr></tbody></table></figure>



<p>I tested the recycle script as well, so if I physically disconnect and reconnect, the docker instance tied to that port is recycled.</p>



<h2 class="wp-block-heading">References</h2>



<ul>
<li><a href="https://www.reddit.com/r/octoprint/comments/mouzdf/ive_been_testing_running_multiple_instances_of/" target="_blank" rel="noreferrer noopener" class="broken_link">https://www.reddit.com/r/octoprint/comments/mouzdf/ive_been_testing_running_multiple_instances_of/</a></li>



<li><a href="https://www.reddit.com/r/octoprint/comments/p3dk12/guidetutorial_multiinstance_octoprint_on_a/" target="_blank" rel="noreferrer noopener" class="broken_link">https://www.reddit.com/r/octoprint/comments/p3dk12/guidetutorial_multiinstance_octoprint_on_a/</a></li>



<li><a href="https://hub.docker.com/r/octoprint/octoprint" target="_blank" rel="noreferrer noopener">https://hub.docker.com/r/octoprint/octoprint</a></li>
</ul>
<p>The post <a rel="nofollow" href="https://krystof.io/octoprint-with-multiple-printers-on-one-ubuntu-linux-mini-pc/">Octoprint with Multiple Printers on One Ubuntu Linux Mini-PC</a> appeared first on <a rel="nofollow" href="https://krystof.io">Krystof.IO</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://krystof.io/octoprint-with-multiple-printers-on-one-ubuntu-linux-mini-pc/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
