diff --git a/pyprusalink/types.py b/pyprusalink/types.py index 742d667..6f1340a 100644 --- a/pyprusalink/types.py +++ b/pyprusalink/types.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import TypedDict +from typing import NotRequired, TypedDict """Types of the v1 API. Source: https://github.com/prusa3d/Prusa-Link-Web/blob/master/spec/openapi.yaml""" @@ -27,15 +27,40 @@ class Capabilities(TypedDict): class VersionInfo(TypedDict): - """Version data.""" + """Version data from /api/version. + + Field availability differs between PrusaLink variants and firmware versions: + + Bundled PrusaLink (Prusa-Firmware-Buddy, all printers): + Always returned: api, server, nozzle_diameter, text, hostname, capabilities + Returned on v6.5.1+ only: firmware, printer + - v6.5.1 (2025-11-11): added on Core One L + - v6.5.3 (2026-03-24): propagated to Core One/MK4/MK3.9/MK3.5 family + - XL (6.4.x track) and MINI (6.4.0): not yet backported + - Source: https://github.com/prusa3d/Prusa-Firmware-Buddy/commit/64b7a21 + + Example response from MK4 firmware 6.4.0 (no firmware/printer fields): + {"api": "2.0.0", "server": "2.1.2", "nozzle_diameter": 0.4, + "text": "PrusaLink", "hostname": "prusa-mk4", + "capabilities": {"upload-by-put": True}} + + Standalone PrusaLink (RPi-based installations): + May return version and sdk per the Prusa-Link-Web OpenAPI spec; these + are never returned by bundled firmware. + + Use dict.get() for any field other than `api` to handle absence safely. + """ api: str - version: str - printer: str - text: str - firmware: str - sdk: str | None - capabilities: Capabilities | None + text: NotRequired[str] + server: NotRequired[str] + hostname: NotRequired[str] + nozzle_diameter: NotRequired[float] + firmware: NotRequired[str] + printer: NotRequired[str] + version: NotRequired[str] + sdk: NotRequired[str] + capabilities: NotRequired[Capabilities] class PrinterInfo(TypedDict): diff --git a/tests/test_prusalink.py b/tests/test_prusalink.py index ceb87d4..085b3ee 100644 --- a/tests/test_prusalink.py +++ b/tests/test_prusalink.py @@ -6,21 +6,47 @@ async def test_get_version(pl, respx_mock): + """Modern firmware (Buddy v6.5.1+) returns firmware and printer fields.""" respx_mock.get(f"{HOST}/api/version").mock( return_value=httpx.Response( 200, json={ "api": "2.0.0", - "version": "0.7.0", - "printer": "1.3.1", - "text": "PrusaLink 0.7.0", - "firmware": "3.10.1-4697", + "server": "2.1.2", + "nozzle_diameter": 0.40, + "text": "PrusaLink", + "hostname": "prusa-core-one", + "firmware": "6.5.3+12780", + "printer": "7.1.0", + "capabilities": {"upload-by-put": True}, }, ) ) result = await pl.get_version() assert result["api"] == "2.0.0" - assert result["firmware"] == "3.10.1-4697" + assert result["firmware"] == "6.5.3+12780" + assert result["printer"] == "7.1.0" + + +async def test_get_version_legacy_firmware(pl, respx_mock): + """Legacy firmware (Buddy