initial commit

Signed-off-by: Florian BOUILLON <f.bouillon@aptatio.com>
This commit is contained in:
Florian Bouillon 2023-04-04 17:49:44 +02:00
commit 9249edf1c4
Signed by: Florian Bouillon
GPG Key ID: E05B3A94178D3A7C
9 changed files with 1480 additions and 0 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
files/*
node_modules/

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
files/

BIN
BambuStudio_ubu64.AppImage Normal file

Binary file not shown.

60
Dockerfile Normal file
View File

@ -0,0 +1,60 @@
#########
# Build #
#########
FROM node:alpine as BUILD_IMAGE
# run as non root user
USER node
# go to user repository
WORKDIR /home/node
# Add package json
ADD --chown=node:node package.json package-lock.json ./
# install dependencies from package lock
RUN npm ci
# Add project files
ADD --chown=node:node . .
# build
RUN npm run build
##############
# Production #
##############
FROM node:latest as PROD_IMAGE
# ADD https://github.com/prusa3d/PrusaSlicer/releases/download/version_2.5.2/PrusaSlicer-2.5.2+linux-x64-GTK3-202303231201.tar.bz2 ./
# RUN tar -xvf PrusaSlicer-2.5.2+linux-x64-GTK3-202303231201.tar.bz2 -C /opt
# ENV PATH /opt/PrusaSlicer-2.5.2+linux-x64-GTK3-202303231201/bin:$PATH
# Install deps
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
prusa-slicer \
&& apt-get remove prusa-slicer -y \
&& rm -rf /var/lib/apt/lists/*
# run as non root user
USER node
# go to work folder
WORKDIR /home/node
ADD --chown=node:node https://github.com/bambulab/BambuStudio/releases/download/v01.05.00.61/Bambu_Studio_linux_fedora_v01.05.00.61_20230314200047.AppImage ./
ENV SLICER_PATH /home/node/Bambu_Studio_linux_fedora_v01.05.00.61_20230314200047.AppImage
RUN chmod +x /home/node/Bambu_Studio_linux_fedora_v01.05.00.61_20230314200047.AppImage
# copy from build image
COPY --chown=node:node --from=BUILD_IMAGE /home/node/node_modules ./node_modules
COPY --chown=node:node --from=BUILD_IMAGE /home/node/configs ./configs
COPY --chown=node:node --from=BUILD_IMAGE /home/node/src ./src
COPY --chown=node:node --from=BUILD_IMAGE /home/node/package.json /home/node/.env* ./
# Expose port
EXPOSE 3000
# run it !
CMD ["npm", "run", "start"]

292
configs/config.ini Normal file
View File

@ -0,0 +1,292 @@
# generated by PrusaSlicer 2.5.2 on 2023-04-04 at 12:15:53 UTC
avoid_crossing_perimeters = 0
avoid_crossing_perimeters_max_detour = 0
bed_custom_model =
bed_custom_texture =
bed_shape = 0x0,180x0,180x180,0x180
bed_temperature = 60
before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n\n
between_objects_gcode =
bottom_fill_pattern = monotonic
bottom_solid_layers = 5
bottom_solid_min_thickness = 0.5
bridge_acceleration = 1000
bridge_angle = 0
bridge_fan_speed = 100
bridge_flow_ratio = 1
bridge_speed = 25
brim_separation = 0.1
brim_type = outer_only
brim_width = 0
clip_multipart_objects = 1
color_change_gcode = M600
colorprint_heights =
compatible_printers_condition_cummulative = "printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.4";"nozzle_diameter[0]!=0.8 and printer_model!=\"XL\" and ! single_extruder_multi_material"
complete_objects = 0
cooling = 1
cooling_tube_length = 5
cooling_tube_retraction = 91.5
default_acceleration = 1000
default_filament_profile = "Prusament PLA"
default_print_profile = 0.15mm QUALITY @MINI
deretract_speed = 40
disable_fan_first_layers = 1
dont_support_bridges = 0
draft_shield = disabled
duplicate_distance = 6
elefant_foot_compensation = 0.2
end_filament_gcode = "; Filament-specific end gcode"
end_gcode = G1 E-1 F2100 ; retract\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+2, max_print_height)} F720 ; Move print head up{endif}\nG1 X178 Y178 F4200 ; park print head\n{if max_layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+30, max_print_height)} F720 ; Move print head further up{endif}\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nM221 S100 ; reset flow\nM900 K0 ; reset LA\nM84 ; disable motors\n; max_layer_z = [max_layer_z]
ensure_vertical_shell_thickness = 1
external_perimeter_acceleration = 800
external_perimeter_extrusion_width = 0.45
external_perimeter_speed = 40
external_perimeters_first = 0
extra_loading_move = -2
extra_perimeters = 0
extruder_clearance_height = 20
extruder_clearance_radius = 35
extruder_colour = ""
extruder_offset = 0x0
extrusion_axis = E
extrusion_multiplier = 1
extrusion_width = 0.45
fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #FF8000
filament_cooling_final_speed = 3.4
filament_cooling_initial_speed = 2.2
filament_cooling_moves = 4
filament_cost = 36.29
filament_density = 1.24
filament_deretract_speed = nil
filament_diameter = 1.75
filament_load_time = 0
filament_loading_speed = 28
filament_loading_speed_start = 3
filament_max_volumetric_speed = 15
filament_minimal_purge_on_wipe_tower = 15
filament_notes = "Affordable filament for everyday printing in premium quality manufactured in-house by Josef Prusa"
filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_retract_before_travel = nil
filament_retract_before_wipe = nil
filament_retract_layer_change = nil
filament_retract_length = nil
filament_retract_lift = nil
filament_retract_lift_above = nil
filament_retract_lift_below = nil
filament_retract_restart_extra = nil
filament_retract_speed = nil
filament_settings_id = "Prusament PLA"
filament_soluble = 0
filament_spool_weight = 201
filament_toolchange_delay = 0
filament_type = PLA
filament_unload_time = 0
filament_unloading_speed = 90
filament_unloading_speed_start = 100
filament_vendor = Prusa Polymers
filament_wipe = nil
fill_angle = 45
fill_density = 20%
fill_pattern = grid
first_layer_acceleration = 600
first_layer_acceleration_over_raft = 0
first_layer_bed_temperature = 60
first_layer_extrusion_width = 0.42
first_layer_height = 0.2
first_layer_speed = 20
first_layer_speed_over_raft = 30
first_layer_temperature = 215
full_fan_speed_layer = 4
fuzzy_skin = none
fuzzy_skin_point_dist = 0.8
fuzzy_skin_thickness = 0.3
gap_fill_enabled = 1
gap_fill_speed = 40
gcode_comments = 0
gcode_flavor = marlin2
gcode_label_objects = 1
gcode_resolution = 0.0125
gcode_substitutions =
high_current_on_filament_swap = 0
host_type = octoprint
infill_acceleration = 1500
infill_anchor = 2.5
infill_anchor_max = 12
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0.45
infill_first = 0
infill_only_where_needed = 0
infill_overlap = 10%
infill_speed = 140
interface_shells = 0
ironing = 0
ironing_flowrate = 15%
ironing_spacing = 0.1
ironing_speed = 15
ironing_type = top
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
layer_height = 0.15
machine_limits_usage = emit_to_gcode
machine_max_acceleration_e = 5000
machine_max_acceleration_extruding = 2000
machine_max_acceleration_retracting = 1250
machine_max_acceleration_travel = 2500
machine_max_acceleration_x = 2500
machine_max_acceleration_y = 2500
machine_max_acceleration_z = 400
machine_max_feedrate_e = 80
machine_max_feedrate_x = 180
machine_max_feedrate_y = 180
machine_max_feedrate_z = 12
machine_max_jerk_e = 10
machine_max_jerk_x = 8
machine_max_jerk_y = 8
machine_max_jerk_z = 2
machine_min_extruding_rate = 0
machine_min_travel_rate = 0
max_fan_speed = 100
max_layer_height = 0.25
max_print_height = 180
max_print_speed = 150
max_volumetric_extrusion_rate_slope_negative = 0
max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_bead_width = 85%
min_fan_speed = 100
min_feature_size = 25%
min_layer_height = 0.07
min_print_speed = 15
min_skirt_length = 4
mmu_segmented_region_max_width = 0
notes =
nozzle_diameter = 0.4
only_retract_when_crossing_perimeters = 0
ooze_prevention = 0
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode
overhangs = 1
parking_pos_retraction = 92
pause_print_gcode = M601
perimeter_acceleration = 1000
perimeter_extruder = 1
perimeter_extrusion_width = 0.45
perimeter_generator = arachne
perimeter_speed = 50
perimeters = 2
physical_printer_settings_id =
post_process =
print_host =
print_settings_id = 0.15mm SPEED @MINI
printer_model = MINI
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MINI\n
printer_settings_id = Original Prusa MINI & MINI+
printer_technology = FFF
printer_variant = 0.4
printer_vendor =
printhost_apikey =
printhost_cafile =
raft_contact_distance = 0.2
raft_expansion = 1.5
raft_first_layer_density = 90%
raft_first_layer_expansion = 3
raft_layers = 0
remaining_times = 1
resolution = 0
retract_before_travel = 1.5
retract_before_wipe = 70%
retract_layer_change = 1
retract_length = 3.2
retract_length_toolchange = 4
retract_lift = 0.2
retract_lift_above = 0
retract_lift_below = 179
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 70
seam_position = aligned
silent_mode = 0
single_extruder_multi_material = 0
single_extruder_multi_material_priming = 1
skirt_distance = 2
skirt_height = 3
skirts = 1
slice_closing_radius = 0.049
slicing_mode = regular
slowdown_below_layer_time = 10
small_perimeter_speed = 25
solid_infill_acceleration = 1500
solid_infill_below_area = 0
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0.45
solid_infill_speed = 140
spiral_vase = 0
standby_temperature_delta = -5
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0"
start_gcode = M862.3 P "[printer_model]" ; printer model check\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\nM104 S170 ; set extruder temp for bed leveling\nM140 S[first_layer_bed_temperature] ; set bed temp\nM109 R170 ; wait for bed leveling temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM204 T1250 ; set travel acceleration\nG28 ; home all without mesh bed level\nG29 ; mesh bed leveling \nM204 T[machine_max_acceleration_travel] ; restore travel acceleration\nM104 S[first_layer_temperature] ; set extruder temp\nG92 E0\nG1 Y-2 X179 F2400\nG1 Z3 F720\nM109 S[first_layer_temperature] ; wait for extruder temp\n\n; intro line\nG1 X170 F1000\nG1 Z0.2 F720\nG1 X110 E8 F900\nG1 X40 E10 F700\nG92 E0\n\nM221 S95 ; set flow
support_material = 0
support_material_angle = 0
support_material_auto = 1
support_material_bottom_contact_distance = 0
support_material_bottom_interface_layers = 0
support_material_buildplate_only = 0
support_material_closing_radius = 2
support_material_contact_distance = 0.2
support_material_enforce_layers = 0
support_material_extruder = 0
support_material_extrusion_width = 0.35
support_material_interface_contact_loops = 0
support_material_interface_extruder = 0
support_material_interface_layers = 2
support_material_interface_pattern = rectilinear
support_material_interface_spacing = 0.2
support_material_interface_speed = 80%
support_material_pattern = rectilinear
support_material_spacing = 2
support_material_speed = 40
support_material_style = grid
support_material_synchronize_layers = 0
support_material_threshold = 50
support_material_with_sheath = 0
support_material_xy_spacing = 60%
temperature = 215
template_custom_gcode =
thick_bridges = 0
thin_walls = 0
threads = 12
thumbnails = 16x16,220x124
thumbnails_format = PNG
toolchange_gcode =
top_fill_pattern = monotoniclines
top_infill_extrusion_width = 0.4
top_solid_infill_acceleration = 800
top_solid_infill_speed = 40
top_solid_layers = 8
top_solid_min_thickness = 0.7
travel_speed = 150
travel_speed_z = 12
use_firmware_retraction = 0
use_relative_e_distances = 1
use_volumetric_e = 0
variable_layer_height = 1
wall_distribution_count = 1
wall_transition_angle = 10
wall_transition_filter_deviation = 25%
wall_transition_length = 100%
wipe = 1
wipe_into_infill = 0
wipe_into_objects = 0
wipe_tower = 0
wipe_tower_bridging = 10
wipe_tower_brim_width = 2
wipe_tower_no_sparse_layers = 0
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 170
wipe_tower_y = 140
wiping_volumes_extruders = 70,70
wiping_volumes_matrix = 0
xy_size_compensation = 0
z_offset = 0

BIN
file.stl Normal file

Binary file not shown.

1025
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

10
package.json Normal file
View File

@ -0,0 +1,10 @@
{
"dependencies": {
"@dzeio/object-util": "^1.5.0",
"express": "^4.18.2"
},
"scripts": {
"start": "node src/main.js",
"build": "true"
}
}

89
src/main.js Normal file
View File

@ -0,0 +1,89 @@
const express = require('express')
const fs = require('fs')
const execSync = require('child_process').execSync;
const { objectMap } = require('@dzeio/object-util')
const server = express()
fs.mkdirSync('files', { recursive: true })
/**
*
* @param {string} data the GCode source
* @returns {number} the time in seconds
*/
function decodeGCode(data) {
const line = data.split('\n').find((it) => it.includes('estimated printing time'))
if (!line) {
console.error('line not found :(')
process.exit(1)
}
const time = line.split('=')[1].trim()
let timeInSec = 0
for (const it of time.split(' ')) {
const lastChar = it.charAt(it.length - 1)
const time = parseInt(it.slice(0, it.length - 1), 10)
console.log(it)
switch (lastChar) {
case 'm':
timeInSec += time * 60
break;
case 's':
timeInSec += time
break;
case 'h':
timeInSec += time * 60 * 60
break;
case 'd':
timeInSec += time * 60 * 60 * 24
break;
default:
throw new Error(`error parsing time ${it} (${time})`)
}
}
console.log('orig', time, 'secs:', timeInSec, 'mins:', timeInSec / 60, 'hours:', timeInSec / 60 / 60, 'days:', timeInSec / 60 / 60 / 24)
return timeInSec
}
server.use ((req, res, next) => {
var data = '';
req.setEncoding('utf8');
req.on('data', function(chunk) {
data += chunk;
});
req.on('end', function() {
req.body = data;
next();
});
});
const path = process.cwd()
server.get('/', (req, res) => {
res.send('send through POST in body the stl')
})
const config = `${path}/configs/config.ini`
server.post('/', (req, res) => {
const overrides = req.query
const file = (Math.random() * 1000000).toFixed(0)
const stlPath = `${path}/files/${file}.stl`
const gcodePath = `${path}/files/${file}.gcode`
console.log(stlPath)
fs.writeFileSync(stlPath, req.body)
const additionnalParams = objectMap(overrides, (v, k) => `--${k} ${v}`).join(' ')
const cmd = `${process.env.SLICER_PATH} --export-gcode ${stlPath} --load ${config} --output ${gcodePath} ${additionnalParams}`
execSync(cmd)
const gcode = fs.readFileSync(gcodePath, 'utf-8')
const time = decodeGCode(gcode)
res.json({ timeToPrint: time, gcode })
// res.sendFile(gcodePath)
})
server.listen(3000, undefined, () => {
console.log(`🚀 Server ready at localhost:3000`);
})