diff --git a/pyprusalink/types.py b/pyprusalink/types.py index 742d667..d18dcf4 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""" @@ -95,10 +95,33 @@ class PrinterStatusInfo(TypedDict): status_connect: StatusInfo | None +class StatusJob(TypedDict, total=False): + """Job summary embedded in the status response. + + All fields are optional per the OpenAPI spec. + """ + + id: int + progress: float + time_printing: int + time_remaining: int + + +class StatusStorage(TypedDict): + """Active storage device embedded in the status response.""" + + path: str + name: str + read_only: bool + free_space: NotRequired[int] + + class PrinterStatus(TypedDict): """Printer status.""" printer: PrinterStatusInfo + job: NotRequired[StatusJob] + storage: NotRequired[StatusStorage] class PrintFileRefs(TypedDict): diff --git a/tests/test_prusalink.py b/tests/test_prusalink.py index 498852f..ab27297 100644 --- a/tests/test_prusalink.py +++ b/tests/test_prusalink.py @@ -65,13 +65,60 @@ async def test_get_status(pl, respx_mock): "speed": 100, "fan_hotend": 1200, "fan_print": 4500, - } + }, + "job": { + "id": 42, + "progress": 55.0, + "time_printing": 1200, + "time_remaining": 980, + }, + "storage": { + "path": "/usb/", + "name": "usb", + "read_only": False, + "free_space": 4202335, + }, }, ) ) result = await pl.get_status() assert result["printer"]["state"] == "PRINTING" assert result["printer"]["temp_nozzle"] == 214.9 + assert result["job"]["id"] == 42 + assert result["job"]["time_remaining"] == 980 + assert result["storage"]["name"] == "usb" + assert result["storage"]["free_space"] == 4202335 + + +async def test_get_status_idle(pl, respx_mock): + """In IDLE state the job key is absent from the response.""" + respx_mock.get(f"{HOST}/api/v1/status").mock( + return_value=httpx.Response( + 200, + json={ + "printer": { + "state": "IDLE", + "temp_nozzle": 27.6, + "target_nozzle": 0.0, + "temp_bed": 24.3, + "target_bed": 0.0, + "axis_z": 0.0, + "flow": 100, + "speed": 100, + "fan_hotend": 0, + "fan_print": 0, + }, + "storage": { + "path": "/usb/", + "name": "usb", + "read_only": False, + }, + }, + ) + ) + result = await pl.get_status() + assert result["printer"]["state"] == "IDLE" + assert "job" not in result async def test_get_job(pl, respx_mock):