Skip to content

Commit

Permalink
Version 2.1 (#8)
Browse files Browse the repository at this point in the history
* Minor fix and plugin rename

* Added some docs

* Added some docs

* Added anonymous statistics

* Added model height option
  • Loading branch information
Molodos authored Jun 4, 2023
1 parent c208604 commit 26fed0a
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 38 deletions.
62 changes: 52 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# Elegoo Neptune 3 Pro/Plus/Max Thumbnails Plugin For Cura
# Elegoo Neptune Thumbnails Plugin For Cura

[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)

Cura 5 plugin for adding G-code thumbnail images for Elegoo Neptune 3 Pro/Plus/Max printers (tested for Elegoo Neptune 3
Pro)
Cura 5 plugin for adding G-code thumbnail images for Elegoo Neptune printers (tested for Elegoo Neptune 3 Pro). I have
not tested every printer, but it seems like based on feedback at least the following models are supported for other
models, see [FAQ](#faq)):

- Elegoo Neptune 3 Pro
- Elegoo Neptune 3 Plus
- Elegoo Neptune 3 Max
- Elegoo Neptune 2

Additional Features:

Expand All @@ -25,32 +31,36 @@ If you like this project, every support is welcome :D
## Installation

1) Download
the [plugin](https://github.com/Molodos/ElegooNeptune3Thumbnails/releases/latest/download/ElegooNeptune3Thumbnails.curapackage)
the [plugin](https://github.com/Molodos/ElegooNeptuneThumbnails/releases/latest/download/ElegooNeptuneThumbnails.curapackage)
2) Drag the `.curapackage` file into the Cura window (like onto the build plate) and restart Cura
<img src="images/cura_drag_plugin.png" width="400">
3) Configure the plugin as shown in [Usage](#usage)
4) Note: This plugin collects anonymous [usage statistics](#usage-statistics) for improvements if not disabled

## Usage

### Possible Options

> **Note:** A maximum of 4 options more than `;includeThumbnail` is supported. \
> **Note:** A maximum of 4 options more than `;includeThumbnail` and `;disableStatistics` is supported. \
> The order in which you specify your options in the start G-code will also be the display
> order (`top-left` > `top-right` > `bottom-left` > `bottom-right`)
| Option | Description |
|----------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| `;disableStatistics` | Disables the collection of anonymous [usage statistics](#usage-statistics) |
| `;includeThumbnail` | Includes a thumbnail of the object to the gcode |
| `;includeTimeEstimate` | Includes the estimated print time in the thumbnail (needs `;includeThumbnail` to be active) |
| `;includeFilamentMetersEstimate` | Includes the estimated filament usage in meters in the thumbnail (needs `;includeThumbnail` to be active) |
| `;includeFilamentGramsEstimate` | Includes the estimated filament usage in grams (for 1.75mm diameter PLA) in the thumbnail (needs `;includeThumbnail` to be active) |
| `;includeLayerHeight` | Includes the layer height in the thumbnail (needs `;includeThumbnail` to be active) | |
| `;includeLayerHeight` | Includes the layer height in the thumbnail (needs `;includeThumbnail` to be active) |
| `;includeModelHeight` | Includes the model height in the thumbnail (needs `;includeThumbnail` to be active) |


### Adding An Option

1) Open printer selection menu and choose `Manage printers` \
<img src="images/cura_manage_printers.png" width="400">
2) Choose your Elegoo Neptune 3 Pro/Plus/Max printer and then `Machine Settings` \
2) Choose your Elegoo Neptune printer and then `Machine Settings` \
<img src="images/cura_manage_printers.png" width="400">
3) At the top of `Start G-code` add your preferred options \
<img src="images/cura_edit_g_code.png" width="600">
Expand All @@ -59,8 +69,23 @@ If you like this project, every support is welcome :D

### Does my printer support this plugin?

I am pretty sure, that the plugin cannot break anything as it just generates a comment with an encoded image in the
G-code, that a printer will only interpret if it can. So I guess just try it out
I am pretty sure, that the plugin cannot break anything as it just generates an encoded image in the G-code, that a
printer will only interpret if it can. So I guess just try it out. To be sure, you should look at your printer for the
start of the print and be ready to cancel the print if it seems to behave weird.

### Thumbnails are not generated, what to do?

1) Make sure, that the plugin is installed correctly. Click "Marketplace" on the top right and then the settings gear on
the top right. The plugin should be displayed under "Installed Plugins"
2) Make sure, that your printer was added to Cura using the official definition for your Neptune printer as a base. If
you for example used an Ender 3 definition as a base and modified it, it won't work because the plugin cannot
identify the printer model

### Why does my Neptune 3 not display thumbnails?

For now, the Neptune 3 model is disabled as it also is disabled in the official Elegoo Cura. I have heard, that support
for thumbnails might have been added to the printer firmware, so I might be adding thumbnails for that printer in the
future, if this can be confirmed somehow.

## Development Guide

Expand All @@ -69,9 +94,26 @@ G-code, that a printer will only interpret if it can. So I guess just try it out
3) Add `UM` folder from https://github.com/Ultimaker/Uranium to base directory (needed as lib)
4) Develop
5) Create package `python -m package_plugin` (package will be
under `packaget_plugin/ElegooNeptune3Thumbnails.curapackage`)
under `package_plugin/ElegooNeptuneThumbnails.curapackage`)
6) Use the `text/test.py` script for testing the formatting of image texts

## Usage Statistics

The plugin will collect some anonymous usage statistics in order to make improvements easier. You can opt out of usage
statistics by adding the option `;disableStatistics` at any time.

Usage statistics are only related to an anonymous statistics id that is generated randomly when you install the plugin.
No personal data is being collected. The statistics data, that is collected, is limited to the following:

- Name of this plugin
- Version of this plugin
- The anonymous statistics id
- The printer type (e.g. "Elegoo Neptune 3 Pro")
- The options you are using (e.g. `;includeLayerHeight`)

> Note: This list might change at some time, so keep an eye on it if you update the plugin. Be aware, that personal data
> will never be added to this list.
## Contribution

This repository is based on [sigathi/ElegooN3Thumbnail](https://github.com/sigathi/ElegooN3Thumbnail) and therefore
Expand Down
4 changes: 2 additions & 2 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Copyright (c) 2023 Molodos
# Copyright (c) 2023 sigathi
# Copyright (c) 2020 LotmaxxSnapshot
# The ElegooNeptune3Thumbnails plugin is released under the terms of the AGPLv3 or higher.
# The ElegooNeptuneThumbnails plugin is released under the terms of the AGPLv3 or higher.

from .elegoo_neptune_3_thumbnails import ElegooNeptune3Thumbnails
from .elegoo_neptune_thumbnails import ElegooNeptune3Thumbnails


def getMetaData():
Expand Down
105 changes: 93 additions & 12 deletions elegoo_neptune_3_thumbnails.py → elegoo_neptune_thumbnails.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Copyright (c) 2023 Molodos
# Copyright (c) 2023 sigathi
# Copyright (c) 2020 DhanOS
# The ElegooNeptune3Thumbnails plugin is released under the terms of the AGPLv3 or higher.
# The ElegooNeptuneThumbnails plugin is released under the terms of the AGPLv3 or higher.
import json
import math
import os
import uuid
from array import array
from ctypes import *
from os import path
from typing import Any

import requests
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QImage, QPainter, QFont, QColor

Expand All @@ -24,6 +28,9 @@ class ElegooNeptune3Thumbnails(Extension):
Main class of the extension
"""

ID: str = "neptune_thumbnails"
VERSION: str = "2.1.0"

colors: dict[str, QColor] = {
"green": QColor(34, 236, 128),
"red": QColor(209, 76, 81),
Expand All @@ -35,6 +42,7 @@ class ElegooNeptune3Thumbnails(Extension):
"own_gray": QColor(200, 200, 200)
}
thumbnail_bg_path: str = path.join(path.dirname(path.realpath(__file__)), "bg_thumbnail.png")
statistics_id_path: str = path.join(path.dirname(path.realpath(__file__)), "statistics_id.json")

def __init__(self):
"""
Expand All @@ -48,6 +56,33 @@ def __init__(self):
# Get a scene handler fo late usage
self.scene: Scene = Application.getInstance().getController().getScene()

# Generate if for anonymous statistics
self.statistics_id: str = self.generate_statistics_id()

@classmethod
def generate_statistics_id(cls) -> str:
"""
Generates an id for anonymous statistics
"""
# Generate if not exists
if not path.exists(cls.statistics_id_path):
random_id: str = str(uuid.uuid4())
with open(cls.statistics_id_path, "w") as file:
file.write(json.dumps(
{
"statistics_id": random_id
},
indent=4
))

# Read and return
try:
with open(cls.statistics_id_path, "r") as file:
stats: dict[str, str] = json.load(file)
return stats.get("statistics_id", "unknown")
except Exception as e:
return "unknown"

def add_snapshot_to_gcode(self, output_device) -> None:
"""
Hook triggered on G-code write to file
Expand All @@ -62,6 +97,7 @@ def add_snapshot_to_gcode(self, output_device) -> None:
for build_plate_number, g_code_list in self.scene.gcode_dict.items():

# Set commands
disable_statistics: bool = False
include_thumbnail: bool = False
include_options: dict[str, int] = {}

Expand All @@ -70,14 +106,18 @@ def add_snapshot_to_gcode(self, output_device) -> None:
# Check for options
if ';includeThumbnail' in g_code:
include_thumbnail = True
if ';disableStatistics' in g_code:
disable_statistics = True
if ';includeTimeEstimate' in g_code:
include_options["time"] = g_code.index(";includeTimeEstimate")
include_options["includeTimeEstimate"] = g_code.index(";includeTimeEstimate")
if ';includeFilamentMetersEstimate' in g_code:
include_options["filament_meters"] = g_code.index(";includeFilamentMetersEstimate")
include_options["includeFilamentMetersEstimate"] = g_code.index(";includeFilamentMetersEstimate")
if ';includeFilamentGramsEstimate' in g_code:
include_options["filament_grams"] = g_code.index(";includeFilamentGramsEstimate")
include_options["includeFilamentGramsEstimate"] = g_code.index(";includeFilamentGramsEstimate")
if ';includeLayerHeight' in g_code:
include_options["layer_height"] = g_code.index(";includeLayerHeight")
include_options["includeLayerHeight"] = g_code.index(";includeLayerHeight")
if ';includeModelHeight' in g_code:
include_options["includeModelHeight"] = g_code.index(";includeModelHeight")

# Get params from G-code
g_code_params_list: list[str] = g_code_list[0].splitlines()
Expand Down Expand Up @@ -107,27 +147,44 @@ def add_snapshot_to_gcode(self, output_device) -> None:
filament_meters: float = float(g_code_params["filament used"][:-1])
est_filament_meters: str = f"{round(filament_meters, 2)}m"
est_filament_grams: str = f"{round(filament_meters * 2.98)}g"
Logger.log("d", f"Estimated filament: {est_filament_meters} {est_filament_grams}")
Logger.log("d", f"Estimated filament: {est_filament_meters}, {est_filament_grams}")

layer_height: str = f"{g_code_params['layer height']}mm"
Logger.log("d", f"Layer height: {layer_height}")

model_height: str = f"▲ {g_code_params['maxz']}mm"
Logger.log("d", f"Model height: {model_height}")

# Send statistics
if not disable_statistics:

# Collect
options: list[str] = ["includeThumbnail"] if include_thumbnail else []
for option, _ in sorted(include_options.items(), key=lambda item: item[1]):
options.append(option)
printer: str = Application.getInstance().getMachineManager().activeMachine.definition.getId()

# Send
self.send_statistics(printer=printer, options=options)

# Add encoded snapshot image if wanted (simage and gimage)
if include_thumbnail:

# Data
data_lines: list[str] = []

# Fill data
for option, priority in sorted(include_options.items(), key=lambda item: item[1]):
if option == "time":
for option, _ in sorted(include_options.items(), key=lambda item: item[1]):
if option == "includeTimeEstimate":
data_lines.append(est_time)
if option == "filament_meters":
if option == "includeFilamentMetersEstimate":
data_lines.append(est_filament_meters)
if option == "filament_grams":
if option == "includeFilamentGramsEstimate":
data_lines.append(est_filament_grams)
if option == "layer_height":
if option == "includeLayerHeight":
data_lines.append(layer_height)
if option == "includeModelHeight":
data_lines.append(model_height)

# Take a screenshot
screenshot: QImage = self.take_screenshot(data_lines)
Expand All @@ -137,10 +194,12 @@ def add_snapshot_to_gcode(self, output_device) -> None:
machine_type = Application.getInstance().getMachineManager().activeMachine.definition.getId()
if machine_type in ["elegoo_neptune_3_pro", "elegoo_neptune_3_plus", "elegoo_neptune_3_max",
"elegoo_neptune_3pro", "elegoo_neptune_3plus", "elegoo_neptune_3max"]:
# Neptune 3 Pro/Plus/Max have another thumbnail format
image_gcode += self.parse_screenshot_new(screenshot, 200, 200, ";gimage:")
image_gcode += self.parse_screenshot_new(screenshot, 160, 160, ";simage:")
image_gcode += "\r"
elif machine_type != "elegoo_neptune_3":
elif machine_type != "elegoo_neptune_3" and "neptune" in machine_type:
# Neptune 3 is not supported for now (also not supported in Elegoo Cura)
image_gcode += self.parse_screenshot(screenshot, 200, 200, ";gimage:")
image_gcode += self.parse_screenshot(screenshot, 160, 160, ";simage:")
image_gcode += "\r"
Expand Down Expand Up @@ -285,3 +344,25 @@ def parse_screenshot_new(cls, img, width, height, img_type) -> str:
Logger.log("d", "Exception == " + str(e))

return result + '\r'

def send_statistics(self, printer: str, options: list[str]) -> None:
"""
Sends anonymous statistics
"""
# Anonymous statistics target url
target_url: str = "http://statistics.molodos.com:8090/cura"

# Collect statistics
statistics: dict[str, Any] = {
"plugin": self.ID,
"version": self.VERSION,
"id": self.statistics_id,
"printer": printer,
"options": options
}

# Send statistics
try:
requests.post(url=target_url, json=statistics, timeout=1)
except Exception:
pass
2 changes: 1 addition & 1 deletion package_plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ElegooNeptune3Thumbnails.curapackage
*.curapackage
2 changes: 1 addition & 1 deletion package_plugin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Copyright (c) 2023 Molodos
# The ElegooNeptune3Thumbnails plugin is released under the terms of the AGPLv3 or higher.
# The ElegooNeptuneThumbnails plugin is released under the terms of the AGPLv3 or higher.
6 changes: 3 additions & 3 deletions package_plugin/__main__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Copyright (c) 2023 Molodos
# The ElegooNeptune3Thumbnails plugin is released under the terms of the AGPLv3 or higher.
# The ElegooNeptuneThumbnails plugin is released under the terms of the AGPLv3 or higher.

import os
import shutil
from zipfile import ZipFile

PACKAGE_PATH: str = os.path.dirname(os.path.realpath(__file__))

PLUGIN_FILES: list[str] = ["__init__.py", "elegoo_neptune_3_thumbnails.py", "bg_thumbnail.png", "LICENSE", "plugin.json", "README.md"]
PLUGIN_FILES: list[str] = ["__init__.py", "elegoo_neptune_thumbnails.py", "bg_thumbnail.png", "LICENSE", "plugin.json", "README.md"]

BUILD_NAME = os.path.join(PACKAGE_PATH, "ElegooNeptune3Thumbnails.curapackage")
BUILD_NAME = os.path.join(PACKAGE_PATH, "ElegooNeptuneThumbnails.curapackage")

PACKAGE_JSON_PATH = os.path.join(PACKAGE_PATH, "package.json")

Expand Down
8 changes: 4 additions & 4 deletions package_plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
"email": "[email protected]",
"website": "https://github.com/Molodos"
},
"description": "Adds Neptune 3 Pro/Plus/Max thumbnail to G-code. Options to add parameters like estimated print time to thumbnail",
"display_name": "Elegoo Neptune 3 Thumbnails",
"description": "Adds Neptune thumbnail to G-code. Options to add parameters like estimated print time to thumbnail",
"display_name": "Elegoo Neptune Thumbnails",
"package_id": "ElegooNeptune3Thumbnails",
"package_type": "plugin",
"package_version": "2.0.0",
"package_version": "2.1.0",
"sdk_version": 8,
"sdk_version_semver": "8.0.0",
"website": "https://github.com/Molodos/ElegooNeptune3Thumbnails"
"website": "https://github.com/Molodos/ElegooNeptuneThumbnails"
}
6 changes: 3 additions & 3 deletions plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Elegoo Neptune 3 Thumbnails",
"name": "Elegoo Neptune Thumbnails",
"author": "Molodos",
"version": "2.0.0",
"description": "Adds Neptune 3 Pro/Plus/Max thumbnail to G-code. Options to add parameters like estimated print time to thumbnail",
"version": "2.1.0",
"description": "Adds Neptune thumbnail to G-code. Options to add parameters like estimated print time to thumbnail",
"api": 8
}
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
PyQt6
requests
2 changes: 1 addition & 1 deletion test/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Copyright (c) 2023 Molodos
# The ElegooNeptune3Thumbnails plugin is released under the terms of the AGPLv3 or higher.
# The ElegooNeptuneThumbnails plugin is released under the terms of the AGPLv3 or higher.
2 changes: 1 addition & 1 deletion test/test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright (c) 2023 Molodos
# The ElegooNeptune3Thumbnails plugin is released under the terms of the AGPLv3 or higher.
# The ElegooNeptuneThumbnails plugin is released under the terms of the AGPLv3 or higher.

import sys
from os import path
Expand Down

0 comments on commit 26fed0a

Please sign in to comment.