Skip to content

Commit

Permalink
Adding an official docker image for Bambu Connect!
Browse files Browse the repository at this point in the history
  • Loading branch information
QuinnDamerell committed May 19, 2024
1 parent ef50344 commit fb2d46d
Show file tree
Hide file tree
Showing 10 changed files with 400 additions and 9 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Publish Docker image

# Only make and deploy new docker images on tagged releases.
on:
release:
types: [published]

jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
# This is needed for the attestation step
id-token: write
attestations: write
steps:
- name: Check out the repo
uses: actions/checkout@v4

# Required for docker multi arch building.
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

# Required for docker multi arch building.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: octoeverywhere/octoeverywhere

- name: Build and push Docker image
id: push
uses: docker/build-push-action@v5
with:
context: .
# These are the platform our ubuntu image base supports
platforms: linux/amd64,linux/arm/v7,linux/arm64
file: ./Dockerfile
push: true
tags: octoeverywhere/octoeverywhere:latest
labels: ${{ steps.meta.outputs.labels }}

# This isn't working, so it's disabled for now.
# - name: Generate artifact attestation
# uses: actions/attest-build-provenance@v1
# with:
# subject-name: octoeverywhere/octoeverywhere
# subject-digest: ${{ steps.push.outputs.digest }}
# push-to-registry: true
3 changes: 2 additions & 1 deletion .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ jobs:
pylint ./moonraker_octoeverywhere/
pylint ./bambu_octoeverywhere/
pylint ./linux_host/
pylint ./py_installer/
pylint ./py_installer/
pylint ./docker_octoeverywhere/
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"boundarydonotcross",
"brotli",
"Buildroot",
"buildx",
"certifi",
"checkin",
"classicwebcam",
Expand Down Expand Up @@ -61,6 +62,7 @@
"Frontends",
"frontendsetup",
"fsensor",
"fstring",
"gcode",
"geteuid",
"getpwnam",
Expand Down
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Start with the lastest ubuntu, for a solid base,
# since we need some advance binaries for things like pillow and ffmpeg.
FROM ubuntu:latest

# We will base ourselves in root, becuase why not.
WORKDIR /root

# Define some user vars we will use for the image.
# These are read in the docker_octoeverywhere module, so they must not change!
ENV USER=root
ENV REPO_DIR=/root/octoeverywhere
ENV VENV_DIR=/root/octoeverywhere-env
# This is a special dir that the user MUST mount to the host, so that the data is persisted.
# If this is not mounted, the printer will need to be re-linked everytime the container is remade.
ENV DATA_DIR=/data/

# Install the required packages.
# Any packages here should be mirrored in the install script - and any optaionl pillow packages done inline.
RUN apt update
RUN apt install -y curl ffmpeg jq python3 python3-pip python3-venv virtualenv libjpeg-dev zlib1g-dev python3-pil python3-pillow

#
# We decided to not run the installer, since the point of the installer is to setup the env, build the launch args, and setup the serivce.
# Instead, we will manually run the smaller subset of commands that are requred to get the env setup in docker.
# Note that if this ever becomes too much of a hassle, we might want to revert back to using the installer, and supporting a headless install.
#
RUN virtualenv -p /usr/bin/python3 ${VENV_DIR}
RUN ${VENV_DIR}/bin/python -m pip install --upgrade pip

# Copy the entire repo into the image, do this as late as possible to avoid rebuilding the image everytime the repo changes.
COPY ./ ${REPO_DIR}/
RUN ${VENV_DIR}/bin/pip3 install --require-virtualenv --no-cache-dir -q -r ${REPO_DIR}/requirements.txt

# For docker, we use our docker_octoeverywhere host to handle the runtime setup and launch of the serivce.
WORKDIR ${REPO_DIR}
# Use the full path to the venv, we msut use this [] notation for our ctlc handler to work in the contianer
ENTRYPOINT ["/root/octoeverywhere-env/bin/python", "-m", "docker_octoeverywhere"]
11 changes: 6 additions & 5 deletions bambu_octoeverywhere/bambuclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ def __init__(self, logger:logging.Logger, config:Config, stateTranslator) -> Non

# Get the required args.
self.Config = config
ipOrHostname = config.GetStr(Config.SectionCompanion, Config.CompanionKeyIpOrHostname, None)
self.PortStr = config.GetStr(Config.SectionCompanion, Config.CompanionKeyPort, None)
self.AccessToken = config.GetStr(Config.SectionBambu, Config.BambuAccessToken, None)
self.PrinterSn = config.GetStr(Config.SectionBambu, Config.BambuPrinterSn, None)
if ipOrHostname is None or self.PortStr is None or self.AccessToken is None or self.PrinterSn is None:
if self.PortStr is None or self.AccessToken is None or self.PrinterSn is None:
raise Exception("Missing required args from the config")

# We use this var to keep track of consecutively failed connections
Expand Down Expand Up @@ -147,7 +146,7 @@ def _ClientWorker(self):
self.Logger.error(f"Failed to connect to the Bambu printer {ipOrHostname}:{self.PortStr} due to a timeout, we will retry in a bit. "+str(e))
else:
# Random other errors.
Sentry.Exception("Failed to connect to the Bambu printer {ipOrHostname}:{self.PortStr}. We will retry in a bit.", e)
Sentry.Exception(f"Failed to connect to the Bambu printer {ipOrHostname}:{self.PortStr}. We will retry in a bit.", e)

# Sleep for a bit between tries.
# The main consideration here is to not log too much when the printer is off. But we do still want to connect quickly, when it's back on.
Expand Down Expand Up @@ -333,13 +332,15 @@ def _GetIpOrHostnameToTry(self) -> str:
self.ConsecutivelyFailedConnectionAttempts = 0

# On the first few attempts, use the expected IP.
# The first attempt will always be attempt 1, since it's reset to 0 and incremented before connecting
# The first attempt will always be attempt 1, since it's reset to 0 and incremented before connecting.
# The IP can be empty, like if the docker container is used, in which case we should always search for the printer.
configIpOrHostname = self.Config.GetStr(Config.SectionCompanion, Config.CompanionKeyIpOrHostname, None)
if self.ConsecutivelyFailedConnectionAttempts < 3:
if configIpOrHostname is not None and len(configIpOrHostname) > 0 and self.ConsecutivelyFailedConnectionAttempts < 3:
return configIpOrHostname

# If we fail too many times, try to scan for the printer on the local subnet, the IP could have changed.
# Since we 100% identify the printer by the access token and printer SN, we can try to scan for it.
self.Logger.info(f"Searching for your Bambu Lab printer {self.PrinterSn}")
ips = NetworkSearch.ScanForInstances_Bambu(self.Logger, self.AccessToken, self.PrinterSn)

# If we get an IP back, it is the printer.
Expand Down
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: '2'
services:
octoeverywhere-bambu-connect:
image: octoeverywhere/octoeverywhere:latest
environment:
# https://octoeverywhere.com/s/access-code
- ACCESS_CODE=XXXXXXXX
# https://octoeverywhere.com/s/bambu-sn
- SERIAL_NUMBER=XXXXXXXXXXXXXXX
# Find using the printer's display
- PRINTER_IP=192.168.1.1
volumes:
# Specify a path mapping for the required persistent storage
- /some/path/on/your/computer:/data

# Add as many printers as you want!
# octoeverywhere-bambu-connect-2:
# image: octoeverywhere/octoeverywhere:latest
# environment:
# # https://octoeverywhere.com/s/access-code
# - ACCESS_CODE=XXXXXXXX
# # https://octoeverywhere.com/s/bambu-sn
# - SERIAL_NUMBER=XXXXXXXXXXXXXXX
# # Find using the printer's display
# - PRINTER_IP=192.168.1.2
# volumes:
# # Specify a path mapping for the required persistent storage
# - /some/path/on/your/computer/printer2:/data
62 changes: 62 additions & 0 deletions docker-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Bambu Connect Docker Support

OctoEverywhere's docker image only works for [Bambu Connect](https://octoeverywhere.com/bambu?source=github_docker_readme) for Bambu Lab 3D printers. If you are using OctoPrint or Klipper, [follow our getting started guide](https://octoeverywhere.com/getstarted?source=github_docker_readme) to install the OctoEverywhere plugin.

Official Docker Image: https://hub.docker.com/r/octoeverywhere/octoeverywhere

## Required Setup Environment Vars

To use the Bambu Connect plugin, you need to get the following information.

- Your printer's Access Code - https://octoeverywhere.com/s/access-code
- Your printer's Serial Number - https://octoeverywhere.com/s/bambu-sn
- Your printer's IP Address - (use the printer's display)

These three values must be set at environment vars when you first run the container. Once the container is run, you don't need to include them again, unless you want to update the values.

- ACCESS_CODE=(code)
- SERIAL_NUMBER=(serial number)
- PRINTER_IP=(ip address)

## Required Persistent Storage

You must map the `/data` folder in your docker container to a directory on your computer so the plugin can write data that will remain between runs. Failure to do this will require relinking the plugin when the container is destroyed or updated.

## Linking Your Bambu Connect Plugin

Once the docker container is running, you need to look at the logs to find the linking URL.

Docker Compose:
`docker-compose logs | grep https://octoeverywhere.com/getstarted`

Docker:
`docker logs bambu-connect | grep https://octoeverywhere.com/getstarted`

# Running The Docker Image

## Using Docker Compose

Using docker compose is the easiest way to run OctoEverywhere's Bambu Connect using docker.

- Install [Docker and Docker Compose](https://docs.docker.com/compose/install/linux/)
- Clone this repo
- Edit the `./docker-compose.yml` file to enter your environment vars
- Run `docker-compose up -d`
- Follow the "Linking Your Bambu Connect Plugin" to link the plugin to your account.

## Using Docker

Docker compose is a fancy wrapper to run docker containers. You can also run docker containers manually.

Use a command like this example, but update the required vars.

`docker pull octoeverywhere/octoeverywhere`
`docker run --name bambu-connect -e ACCESS_CODE=<code> -e SERIAL_NUMBER=<serial number> -e PRINTER_IP=<ip address> -v /your/local/path:/data -d octoeverywhere/octoeverywhere`

Follow the "Linking Your Bambu Connect Plugin" to link the plugin to your account.

## Building The Image Locally

You can build the docker image locally if you prefer, use the following command.

`docker build -t octoeverywhere .`
1 change: 1 addition & 0 deletions docker_octoeverywhere/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Need to make this a module
Loading

0 comments on commit fb2d46d

Please sign in to comment.