Skip to content

Commit 3222150

Browse files
committed
add mmu_ace component
1 parent 3231898 commit 3222150

File tree

5 files changed

+985
-28
lines changed

5 files changed

+985
-28
lines changed

files/4-apps/home/rinkhals/apps/40-moonraker/app.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ debug() {
2828
. bin/activate
2929

3030
cp -rf kobra.py moonraker/moonraker/components/kobra.py
31+
cp -rf mmu_ace.py moonraker/moonraker/components/mmu_ace.py
3132
python /opt/rinkhals/scripts/process-cfg.py moonraker.conf > /userdata/app/gk/printer_data/config/moonraker.generated.conf
3233
HOME=/userdata/app/gk python ./moonraker/moonraker/moonraker.py -c /userdata/app/gk/printer_data/config/moonraker.generated.conf $@
3334
}

files/4-apps/home/rinkhals/apps/40-moonraker/kobra.py

Lines changed: 166 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,27 @@
55
import time
66
import logging
77
import subprocess
8+
import shlex
9+
import ast
810
import paho.mqtt.client as paho
911

1012
from ..utils import Sentinel
1113
from .power import PowerDevice
14+
from ..common import WebRequest
15+
16+
from typing import (
17+
TYPE_CHECKING,
18+
Any,
19+
Union,
20+
Optional,
21+
Dict,
22+
List,
23+
TypeVar,
24+
Mapping,
25+
Callable,
26+
Coroutine
27+
)
28+
FlexCallback = Callable[..., Optional[Coroutine]]
1229

1330

1431
def shell(command):
@@ -37,6 +54,11 @@ class Kobra:
3754
_remote_mode = None
3855
_total_layer = 0
3956

57+
# GCode handlers
58+
gcode_handlers: dict[str, FlexCallback] = {}
59+
status_patchers: List[Callable[[dict], dict]] = []
60+
print_data_patchers: List[Callable[[dict], dict]] = []
61+
4062
def __init__(self, config):
4163
self.server = config.get_server()
4264
self.power = self.server.load_component(self.server.config, 'power')
@@ -70,6 +92,7 @@ def tool_function(*args):
7092
logging.info('Starting Kobra patching...')
7193

7294
self.patch_status_updates()
95+
self.patch_gcode_handler()
7396
self.patch_network_interfaces()
7497
self.patch_spoolman()
7598
self.patch_simplyprint()
@@ -172,22 +195,50 @@ def mqtt_print_file(self, file):
172195
vibration_compensation = self.get_app_property('40-moonraker', 'mqtt_print_vibration_compensation').lower() == 'true'
173196
flow_calibration = self.get_app_property('40-moonraker', 'mqtt_print_flow_calibration').lower() == 'true'
174197

175-
payload = f"""{{
176-
"type": "print",
177-
"action": "start",
178-
"msgid": "{uuid.uuid4()}",
179-
"timestamp": {round(time.time() * 1000)},
180-
"data": {{
181-
"taskid": "-1",
182-
"filename": "{file}",
183-
"filetype": 1,
184-
"task_settings": {{
185-
"auto_leveling": {'1' if auto_leveling else '0'},
186-
"vibration_compensation": {'1' if vibration_compensation else '0'},
187-
"flow_calibration": {'1' if flow_calibration else '0'}
188-
}}
189-
}}
190-
}}"""
198+
print_request = {
199+
'type': 'print',
200+
'action': 'start',
201+
'msgid': str(uuid.uuid4()),
202+
'timestamp': int(time.time() * 1000),
203+
'data': {
204+
'taskid': '-1',
205+
'filename': file,
206+
'filetype': 1,
207+
'task_settings': {
208+
'auto_leveling': 1 if auto_leveling else 0,
209+
'vibration_compensation': 1 if vibration_compensation else 0,
210+
'flow_calibration': 1 if flow_calibration else 0
211+
}
212+
}
213+
}
214+
215+
print_data = print_request["data"]
216+
217+
for patcher in self.print_data_patchers:
218+
print_data = patcher(print_data)
219+
220+
print_request["data"] = print_data
221+
222+
logging.info(f'[Kobra] print data : {json.dumps(print_data)}')
223+
224+
payload = json.dumps(print_request)
225+
226+
# payload = f"""{{
227+
# "type": "print",
228+
# "action": "start",
229+
# "msgid": "{uuid.uuid4()}",
230+
# "timestamp": {round(time.time() * 1000)},
231+
# "data": {{
232+
# "taskid": "-1",
233+
# "filename": "{file}",
234+
# "filetype": 1,
235+
# "task_settings": {{
236+
# "auto_leveling": {'1' if auto_leveling else '0'},
237+
# "vibration_compensation": {'1' if vibration_compensation else '0'},
238+
# "flow_calibration": {'1' if flow_calibration else '0'}
239+
# }}
240+
# }}
241+
# }}"""
191242

192243
self.mqtt_print_report = False
193244
self.mqtt_print_error = None
@@ -284,8 +335,16 @@ def patch_status(self, status):
284335
# Remove path prefix from file path
285336
status['virtual_sdcard']['file_path'] = status['virtual_sdcard']['file_path'].replace('/useremain/app/gk/gcodes/', '')
286337

338+
for patcher in self.status_patchers:
339+
status = patcher(status)
340+
287341
return status
288342

343+
def register_status_patcher(self, patcher: Callable[[dict], dict]):
344+
self.status_patchers.append(patcher)
345+
346+
def register_print_data_patcher(self, patcher: Callable[[dict], dict]):
347+
self.print_data_patchers.append(patcher)
289348

290349
def patch_status_updates(self):
291350
from .klippy_apis import KlippyAPI
@@ -388,27 +447,106 @@ def get_klippy_info(me):
388447
setattr(Server, 'get_klippy_info', wrap_get_klippy_info(Server.get_klippy_info))
389448
logging.debug(f' After: {Server.get_klippy_info}')
390449

391-
def patch_mqtt_print(self):
450+
def register_gcode_handler(self, cmd, callback: FlexCallback):
451+
logging.info(f'> Registering gcode handler for {cmd}...')
452+
self.gcode_handlers[cmd.upper()] = callback
453+
454+
def patch_gcode_handler(self):
392455
from .klippy_apis import KlippyAPI
456+
from .klippy_connection import KlippyConnection
457+
458+
async def handle_gcode(me, script, delegate_run_gcode: Callable[[], Coroutine]):
459+
parts = [s.strip() for s in shlex.split(script.strip()) if s.strip()]
460+
logging.warning(f"hook on gcode received: {json.dumps(parts)}")
461+
cmd = parts[0]
462+
463+
logging.warning(f"hook on gcode cmd: {cmd}")
464+
handlers = self.gcode_handlers.keys()
465+
# join handlers
466+
handlers = ', '.join(handlers)
467+
logging.warning(f"hook on gcode handlers: {handlers}")
468+
469+
if cmd in self.gcode_handlers:
470+
logging.warning(f"hook on gcode cmd found: {cmd}")
471+
args = {}
472+
for part in parts[1:]:
473+
if '=' in part:
474+
key, value = part.split('=', 1)
475+
args[key] = value
476+
else:
477+
args[part] = None
478+
479+
logging.warning(f"hook on gcode args: {json.dumps(args)}")
480+
result = await self.gcode_handlers[cmd](args, delegate_run_gcode)
481+
result_str = "None" if result is None else "Any"
482+
logging.warning(f"hook on gcode result: {result_str}")
483+
484+
if result is None:
485+
return None
486+
487+
return await result
488+
else:
489+
logging.warning(f"hook on gcode cmd not found: {cmd}")
490+
return await delegate_run_gcode()
491+
492+
def wrap_request(original_request: KlippyConnection.request):
493+
async def request(me: KlippyConnection, web_request: WebRequest):
494+
logging.warning(f"hook on request")
495+
496+
rpc_method = web_request.get_endpoint()
497+
if rpc_method == "gcode/script":
498+
499+
script = web_request.get_str('script', "")
500+
if script:
501+
async def delegate_run_gcode():
502+
return await original_request(me, web_request)
503+
504+
return await handle_gcode(me, script, delegate_run_gcode)
505+
506+
return await original_request(me, web_request)
507+
508+
return request
509+
510+
def wrap_run_gcode(original_run_gcode: KlippyAPI.run_gcode):
511+
async def run_gcode(me: KlippyAPI, script: str, default: Any = Sentinel.MISSING):
512+
logging.warning(f"hook on run gcode: {script}")
513+
514+
async def delegate_run_gcode():
515+
return await original_run_gcode(me, script, default)
516+
517+
return await handle_gcode(me, script, delegate_run_gcode)
393518

394-
def wrap_run_gcode(original_run_gcode):
395-
async def run_gcode(me, script, default = Sentinel.MISSING):
396-
if self.is_goklipper_running() and script.startswith('SDCARD_PRINT_FILE'):
397-
self._total_layer = 0
398-
filename = re.search("FILENAME=\"([^\"]+)\"$", script)
399-
filename = filename[1] if filename else None
400-
if filename and self.is_using_mqtt():
401-
self.mqtt_print_file(filename)
402-
return None
403-
return await original_run_gcode(me, script, default)
404519
return run_gcode
405520

406-
logging.info('> Send prints to MQTT...')
521+
logging.info('> Adding gcode handler...')
522+
523+
logging.debug(f' Before: {KlippyConnection.request}')
524+
setattr(KlippyConnection, 'request', wrap_request(KlippyConnection.request))
525+
logging.debug(f' After: {KlippyConnection.request}')
407526

408527
logging.debug(f' Before: {KlippyAPI.run_gcode}')
409528
setattr(KlippyAPI, 'run_gcode', wrap_run_gcode(KlippyAPI.run_gcode))
410529
logging.debug(f' After: {KlippyAPI.run_gcode}')
411530

531+
def patch_mqtt_print(self):
532+
async def handle_gcode_print_file(args: dict, delegate_run_gcode):
533+
logging.info(f'[Kobra] Print file: {args}')
534+
if self.is_goklipper_running():
535+
self._total_layer = 0
536+
filename = args["FILENAME"] if "FILENAME" in args else None
537+
logging.info(f'[Kobra] Print file: {filename}')
538+
539+
if filename and self.is_using_mqtt():
540+
logging.info(f'[Kobra] MQTT print file: {filename}')
541+
self.mqtt_print_file(filename)
542+
return None
543+
544+
logging.info(f'[Kobra] Not MQTT print file: {filename}')
545+
return await delegate_run_gcode()
546+
547+
logging.info('> Send prints to MQTT...')
548+
self.register_gcode_handler('SDCARD_PRINT_FILE', handle_gcode_print_file)
549+
412550
def patch_bed_mesh(self):
413551
from .klippy_connection import KlippyConnection
414552

0 commit comments

Comments
 (0)