source/projects/tentacles/src/gcode.py
Reid 'arrdem' McKenzie 89ac85693d m0ar
2024-02-06 11:19:46 -07:00

103 lines
2.5 KiB
Python

#!/usr/bin/env python3
from pathlib import Path
import re
from typing import Optional, Tuple
from attrs import define
OPTION_PATTERN = re.compile("; (?P<key>[a-z0-9_]+) = (?P<value>.*?)\n")
def parse_prusa_config_str(content: str) -> dict:
kvs = {}
iter = re.finditer(OPTION_PATTERN, content)
while m := next(iter, None):
if m.group("key") == "prusaslicer_config" and m.group("value") == "begin":
break
while m := next(iter, None):
if m.group("key") == "prusaslicer_config" and m.group("value") == "end":
break
else:
kvs[m.group("key")] = m.group("value")
return kvs
def parse_prusa_config(p: Path):
with open(p) as fp:
return parse_prusa_config_str(fp.read())
@define
class GcodeAnalysis:
max_x: int
max_y: int
max_z: int
max_bed: int
max_end: int
filament: str
nozzle: int
def parse_point(point: str) -> Tuple[int, int]:
a, b = point.split("x")
return int(a), int(b)
def parse_bed_shape(coords: str) -> Tuple[int, int]:
# Note, these are clockwise from 0, 0
a, b, c, d = coords.split(",")
dx, _ = parse_point(a)
_, dy = parse_point(b)
x, y = parse_point(c)
return x + dx, y + dy
def analyze_gcode_str(text: str) -> Optional[GcodeAnalysis]:
opts = parse_prusa_config_str(text)
kwargs = {}
if "bed_shape" in opts:
max_x, max_y = parse_bed_shape(opts["bed_shape"])
kwargs["max_x"] = max_x
kwargs["max_y"] = max_y
else:
return None
if "max_print_height" in opts:
kwargs["max_z"] = int(opts["max_print_height"])
else:
return None
if "first_layer_bed_temperature" in opts:
kwargs["max_bed"] = int(opts["first_layer_bed_temperature"])
elif "bed_temperature" in opts:
kwargs["max_bed"] = int(opts["bed_temperature"])
else:
return None
if "first_layer_temperature" in opts:
kwargs["max_end"] = int(opts["first_layer_temperature"])
elif "temperature" in opts:
kwargs["max_end"] = int(opts["temperature"])
else:
return None
if "filament_type" in opts:
kwargs["filament"] = opts["filament_type"]
else:
return None
if "nozzle_diameter" in opts:
kwargs["nozzle"] = float(opts["nozzle_diameter"])
else:
return None
return GcodeAnalysis(**kwargs)
def analyze_gcode_file(p: Path) -> Optional[GcodeAnalysis]:
with open(p) as fp:
return analyze_gcode_str(fp.read())