diff --git a/docs/external_api/integrations.md b/docs/external_api/integrations.md index 63b9a14b3..922780946 100644 --- a/docs/external_api/integrations.md +++ b/docs/external_api/integrations.md @@ -1698,3 +1698,167 @@ Not Available } ``` /// + +## Lane Data +Lane data component can be used by third-parties(slicers) to grab information about what filament is loaded into filament changers lanes. + +The following endpoints are available when the `[lane_data]` component has been configured. + +### Set Lane Data +Allows klipper add-ons to populate filament information for what kinda of filament is loaded into filament changers lanes(aka tools, T0, T1, etc). +```{.http .apirequest title="HTTP Request"} +POST /machine/set_lane_data +Content-Type: application/json + +{ + "lane1": { + "color": "#122B44", + "td": 4.0, + "material": "ASA", + "bed_temp": 105, + "nozzle_temp":245, + "scan_time": "2025-09-14T03:13:27.189383Z", + "lane": "1" + }, + "lane2": { + "color": "#122B44", + "td": 4.0, + "material": "ASA", + "bed_temp": 105, + "nozzle_temp":245, + "scan_time": "2025-09-14T03:13:27.189383Z", + "lane": "0" + } + +} +``` +```{.json .apirequest title="JSON-RPC Request"} +{ + "jsonrpc": "2.0", + "method": "machine.set_lane_data", + "params": { + "lane1": { + "color": "#122B44", + "td": 4.0, + "material": "ASA", + "bed_temp": 105, + "nozzle_temp":245, + "scan_time": "2025-09-14T03:13:27.189383Z", + "lane": "1" + }, + "lane2": { + "color": "#122B44", + "td": 4.0, + "material": "ASA", + "bed_temp": 105, + "nozzle_temp":245, + "scan_time": "2025-09-14T03:13:27.189383Z", + "lane": "0" + } + }, + "id": 4654 +} +``` +/// api-parameters + open: True +| Name | Type | Default | Description | +| ------------- | :----: | -------- | ------------------------------------------------- | +| `` | string | REQUIRED | Object of `Lane Data` information, name should be | +| | | | unique for each lane/slot. Multiple lanes can be |^ +| | | | provided at once when passed in as an array. |^ +| | | | #post-lane-data-spec |+ + +| Name | Type | Default | Description | +| ------------- | :-------------: | -------- | ----------------------------------------------------- | +| `color ` | string | REQUIRED | Current color filament loaded in lane/slot. | +| `td` | float \| int | null | Current transmission distance(TD) of filament | +| | | | loaded in lane/slot. |^ +| `material` | string | REQUIRED | Current filament material type loaded into lane/slot. | +| `bed_temp` | int | REQUIRED | Bed temperature for filament loaded. | +| `nozzle_temp` | int | REQUIRED | Nozzle temperature to set for filament loaded. | +| `scan_time` | datetime string | null | Last scan time if filament color and TD was scanned | +| | | | with a TD-1 device |^ +| `lane` | string | REQUIRED | Current tool mapping for lane/slot. eg. T0/T1/T2/etc. | +{ #post-lane-data-spec} Lane Data + +/// + +```{.json .apiresponse title="Example Response"} +{ + "status": "ok" +} +``` +/// api-response-spec + open: True +| Field | Type | Description | +| -------- | :----: | ----------------------------------------- | +| `status` | string | Returns "ok" if valid data was provided. | +| | | Returns "error" if provided is not valid. |^ +/// +### Get Lane Data +Returns an array of all lane data information that has been posted to `/machine/set_lane_data` endpoint. + +```{.http .apirequest title="HTTP Request"} +GET /machine/lane_data +``` +```{.json .apirequest title="JSON-RPC Request"} +{ + "jsonrpc": "2.0", + "method": "machine.lane_data", + "id": 4654 +} +``` +/// collapse-code +```{.json .apiresponse title="Example Response"} +{ + "lanes": { + "lane1": { + "color": "#122B44", + "td": 4.0, + "material": "ASA", + "bed_temp": 105, + "nozzle_temp":245, + "scan_time": "2025-09-14T03:13:27.189383Z", + "lane": "0" + }, + "lane2": { + "color": "#122B44", + "td": 4.0, + "material": "ASA", + "bed_temp": 105, + "nozzle_temp":245, + "scan_time": "2025-09-14T03:13:27.189383Z", + "lane": "0" + } + } +} +``` +/// + +/// api-response-spec + open: True +| Field | Type | Description | +| ------- | :------: | -------------------------------- | +| `lanes` | [object] | An array of `Lane Name` objects. | +| | | #get-lane-name-spec |+ + +| Field | Type | Description | +| ------------- | :----: | ------------------------------------- | +| `` | string | Object of `Lane` information, name is | +| | | unique for each object. |^ +| | | #get-lane-data-spec |+ +{ #get-lane-name-spec} Lane Name + + +| Field | Type | Description | +| ------------- | :-------------: | ----------------------------------------------------- | +| `color ` | string | Current color filament loaded in lane/slot. | +| `td` | float \| int | Current transmission distance(TD) of filament | +| | | loaded in lane/slot. Could also return null. |^ +| `material` | string | Current filament material type loaded into lane/slot. | +| `bed_temp` | int | Bed temperature for filament loaded. | +| `nozzle_temp` | int | Nozzle temperature to set for filament loaded. | +| `scan_time` | datetime string | Last scan time if filament color and TD was scanned | +| | | with a TD-1 device. Could also return null. |^ +| `lane` | string | Current tool mapping for lane/slot. eg. T0/T1/T2/etc. | +{ #get-lane-data-spec} Lane Data \ No newline at end of file diff --git a/moonraker/components/lane_data.py b/moonraker/components/lane_data.py new file mode 100644 index 000000000..e575e537f --- /dev/null +++ b/moonraker/components/lane_data.py @@ -0,0 +1,55 @@ +# Support for posting filament changer data to so third-parties(slicers) can +# grab this information to use. +# +# Copyright (C) 2025 AJAX3D and Jim Madill +# +# This file may be distributed under the terms of the GNU GPLv3 license + +import asyncio +import logging + +class LaneDataStore: + def __init__(self, config): + self._config = config + self._server = config.get_server() + self._logger = logging.getLogger("lane_data") + self._loop = asyncio.get_event_loop() + self._lane_data = {} # key: lane number or id, value: data dict + + async def initialize(self): + self._server.register_endpoint( + "/machine/lane_data", ["GET"], self._handle_get_data + ) + self._server.register_endpoint( + "/machine/set_lane_data", ["POST"], self._handle_set_data + ) + + async def _handle_get_data(self, request): + return { + "status": "ok", + "lanes": self._lane_data + } + + async def _handle_set_data(self, request): + data = request.get("data", {}) + if not isinstance(data, dict): + return {"status": "error", "error": "Invalid JSON data."} + + for lane_id, lane_info in data.items(): + if not isinstance(lane_info, dict): + continue + self._lane_data[lane_id] = { + "color": lane_info.get("color"), + "td": lane_info.get("td", None), + "material": lane_info.get("material"), + "bed_temp": lane_info.get("bed_temp"), + "nozzle_temp": lane_info.get("nozzle_temp"), + "scan_time": lane_info.get("scan_time", None), + "lane": lane_info.get("lane"), + } + return {"status": "ok"} + +def load_component(config): + component = LaneDataStore(config) + asyncio.get_event_loop().create_task(component.initialize()) + return component