Grotti 3.4.0: Dateien umbenennen, Bedarf/PLA-Match, Pause- und gklib-Fixes.

This commit is contained in:
Dominic Gundel committed 2026-10-18 21:36:12 +02:00
1 parent 67a89d1794
commit dd0e7ebc6b
16 files changed
+430 -58

No files matched your search

+24
View File
@@ -63,6 +63,30 @@ class BedarfTests(unittest.TestCase):
out = compute(conn)
self.assertEqual(out["shortfall"], [])
def test_slicer_hex_matches_named_stock(self):
"""Slice #26A69A vs. Spule „Grau“ — 1 kg reicht, kein Fehlalarm."""
conn = MagicMock()
conn.execute.side_effect = self._rows(
[
{
"id": 1,
"spool_id": None,
"repeat_total": 1,
"repeat_done": 0,
"weight_g": 49.23,
"filaments": [{"type": "PLA", "color": "#26A69A"}],
"spool_material": None,
"spool_color": None,
},
],
[
{"material_type": "PLA", "color": "Grau", "remaining_g": 1000.0},
],
)
out = compute(conn)
self.assertEqual(out["shortfall"], [])
self.assertAlmostEqual(out["needed"][0]["weight_g"], 49.23)
if __name__ == "__main__":
unittest.main()
+44
View File
@@ -0,0 +1,44 @@
"""Einfarbig: filament_colour_type strippen; Multicolor unangetastet."""
import unittest
from grotti.parse import gcode_is_multicolor, prepare_rinkhals_gcode, strip_filament_colour_type
class ColourTypeStripTest(unittest.TestCase):
def test_strip_single_color(self):
raw = (
b"; generated by OrcaSlicer 2.3.0\n"
b"; filament_colour = #26A69A\n"
b"; filament_colour_type = 1\n"
b"G28\n"
b"T0\n"
b"G1 X10\n"
)
out = strip_filament_colour_type(raw)
self.assertNotIn(b"filament_colour_type", out)
self.assertIn(b"filament_colour = #26A69A", out)
self.assertFalse(gcode_is_multicolor(raw))
def test_keep_multicolor(self):
raw = (
b"; generated by OrcaSlicer 2.3.0\n"
b"; filament_colour = #111111;#222222\n"
b"; filament_colour_type = 0;1\n"
b"T0\n"
b"G1 X1\n"
b"T1\n"
b"G1 X2\n"
)
self.assertTrue(gcode_is_multicolor(raw))
out = strip_filament_colour_type(raw)
self.assertIn(b"filament_colour_type = 0;1", out)
def test_prepare_strips_single(self):
raw = b"; filament_colour_type = 1\nG28\nT0\n"
out = prepare_rinkhals_gcode(raw)
self.assertNotIn(b"filament_colour_type", out)
if __name__ == "__main__":
unittest.main()
+41 -7
View File
@@ -11,11 +11,43 @@ class FilamentOutHintTests(unittest.TestCase):
self.assertEqual(code, "message")
self.assertIn("10107", text)
def test_active_filament_empty(self):
code, text = filament_out_hint({"active_filament": {"empty": True}})
def test_reason_for_pause(self):
code, text = filament_out_hint({"reason_for_pause": "Filament runout"}, "")
self.assertEqual(code, "reason")
self.assertIn("runout", text.lower())
def test_active_filament_empty_needs_active_tool(self):
code, text = filament_out_hint({
"tool": 1,
"gate_status": [1, 1, 1, 1],
"active_filament": {"empty": True},
})
self.assertEqual(code, "active_empty")
self.assertIn("leer", text.lower())
def test_anycubic_empty_without_tool_is_not_runout(self):
# Live A2/Kobra 3: empty=true, tool=-1, alle gate_status 0 — auch beim Druck
code, text = filament_out_hint({
"tool": -1,
"gate": -1,
"is_paused": False,
"gate_status": [0, 0, 0, 0],
"active_filament": {"empty": True, "material": ""},
"reason_for_pause": "",
})
self.assertIsNone(code)
self.assertIsNone(text)
def test_manual_pause_anycubic_not_material(self):
code, text = filament_out_hint({
"tool": -1,
"is_paused": True,
"gate_status": [0, 0, 0, 0],
"active_filament": {"empty": True},
}, "paused")
self.assertIsNone(code)
self.assertIsNone(text)
def test_gate_status_zero_for_tool(self):
code, text = filament_out_hint({
"tool": 2,
@@ -25,13 +57,15 @@ class FilamentOutHintTests(unittest.TestCase):
self.assertEqual(code, "gate_empty")
self.assertIn("3", text)
def test_mmu_paused_without_active_type(self):
def test_all_gates_zero_not_empty_signal(self):
# Anycubic: gate_status oft durchgängig 0 — kein Runout-Beweis
code, text = filament_out_hint({
"is_paused": True,
"active_filament": {},
"tool": 0,
"gate_status": [0, 0, 0, 0],
"active_filament": {"type": "PLA", "empty": False},
})
self.assertEqual(code, "mmu_paused")
self.assertTrue(text)
self.assertIsNone(code)
self.assertIsNone(text)
def test_no_hint_for_plain_pause(self):
code, text = filament_out_hint({"tool": 0, "gate_status": [1, 1]}, "paused")
+20
View File
@@ -17,6 +17,12 @@ class ProfileMatchTests(unittest.TestCase):
def test_empty_profile_always_ok(self):
self.assertTrue(store._profile_matches("", "Sunlu PLA Meta"))
def test_base_profile_helpers(self):
self.assertFalse(store._profile_has_variant("Sunlu PLA"))
self.assertTrue(store._profile_has_variant("Sunlu PLA Meta"))
self.assertEqual(store._profile_base_type("Sunlu PLA"), "pla")
self.assertEqual(store._profile_base_type("Generic PETG"), "petg")
class MatchSpoolsTests(unittest.TestCase):
def setUp(self):
@@ -37,8 +43,22 @@ class MatchSpoolsTests(unittest.TestCase):
"material_name": "sunlu pla matte",
"ace_slot": 2,
},
{
"spool_id": 3,
"material_type": "pla",
"color": "",
"remaining_g": 900,
"material_name": "eryone pla",
"ace_slot": None,
},
]
def test_base_sunlu_pla_matches_plain_pla_not_meta(self):
need = {"profile": "Sunlu PLA", "material_type": "pla", "color": "", "paint_index": 0}
matched = store._match_spools_for_need(need, self.have)
ids = {m["spool_id"] for m in matched}
self.assertEqual(ids, {3}) # Eryone PLA; Meta/Matte nicht
def test_picks_meta_not_matte(self):
need = {"profile": "Sunlu PLA Meta", "material_type": "pla", "color": "", "paint_index": 0}
matched = store._match_spools_for_need(need, self.have)