flashforge-python-api 1.0.2__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flashforge/__init__.py +70 -29
- flashforge/api/__init__.py +1 -0
- flashforge/api/constants/__init__.py +1 -0
- flashforge/api/constants/commands.py +1 -0
- flashforge/api/constants/endpoints.py +7 -0
- flashforge/api/controls/__init__.py +1 -0
- flashforge/api/controls/control.py +64 -61
- flashforge/api/controls/files.py +28 -26
- flashforge/api/controls/info.py +84 -85
- flashforge/api/controls/job_control.py +120 -82
- flashforge/api/controls/temp_control.py +14 -11
- flashforge/api/misc/__init__.py +1 -1
- flashforge/api/network/__init__.py +2 -1
- flashforge/api/network/utils.py +7 -8
- flashforge/client.py +185 -64
- flashforge/discovery/__init__.py +30 -3
- flashforge/discovery/discovery.py +641 -308
- flashforge/models/__init__.py +11 -10
- flashforge/models/machine_info.py +225 -100
- flashforge/models/responses.py +103 -43
- flashforge/tcp/__init__.py +30 -17
- flashforge/tcp/a3_client.py +408 -0
- flashforge/tcp/a4_client.py +300 -0
- flashforge/tcp/ff_client.py +93 -90
- flashforge/tcp/gcode/__init__.py +4 -2
- flashforge/tcp/gcode/a3_gcode_controller.py +109 -0
- flashforge/tcp/gcode/gcode_controller.py +48 -36
- flashforge/tcp/gcode/gcodes.py +7 -1
- flashforge/tcp/parsers/__init__.py +11 -11
- flashforge/tcp/parsers/endstop_status.py +103 -132
- flashforge/tcp/parsers/location_info.py +26 -13
- flashforge/tcp/parsers/print_status.py +49 -56
- flashforge/tcp/parsers/printer_info.py +38 -48
- flashforge/tcp/parsers/temp_info.py +46 -47
- flashforge/tcp/parsers/thumbnail_info.py +65 -40
- flashforge/tcp/tcp_client.py +296 -293
- flashforge_python_api-1.2.0.dist-info/METADATA +133 -0
- flashforge_python_api-1.2.0.dist-info/RECORD +46 -0
- {flashforge_python_api-1.0.2.dist-info → flashforge_python_api-1.2.0.dist-info}/WHEEL +1 -1
- flashforge_python_api-1.0.2.dist-info/METADATA +0 -284
- flashforge_python_api-1.0.2.dist-info/RECORD +0 -43
- {flashforge_python_api-1.0.2.dist-info → flashforge_python_api-1.2.0.dist-info}/entry_points.txt +0 -0
- {flashforge_python_api-1.0.2.dist-info → flashforge_python_api-1.2.0.dist-info}/licenses/LICENSE +0 -0
flashforge/api/controls/files.py
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"""
|
|
2
2
|
FlashForge Python API - Files Module
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
import base64
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
6
7
|
|
|
7
8
|
import aiohttp
|
|
9
|
+
from pydantic import ValidationError
|
|
8
10
|
|
|
9
11
|
from ...models.machine_info import FFGcodeFileEntry
|
|
10
|
-
from ...models.responses import
|
|
12
|
+
from ...models.responses import GCodeListResponse, ThumbnailResponse
|
|
11
13
|
from ..constants.endpoints import Endpoints
|
|
12
14
|
from ..network.utils import NetworkUtils
|
|
13
|
-
from pydantic import ValidationError
|
|
14
15
|
|
|
15
16
|
if TYPE_CHECKING:
|
|
16
17
|
from ...client import FlashForgeClient
|
|
@@ -25,34 +26,34 @@ class Files:
|
|
|
25
26
|
def __init__(self, client: "FlashForgeClient"):
|
|
26
27
|
"""
|
|
27
28
|
Creates an instance of the Files class.
|
|
28
|
-
|
|
29
|
+
|
|
29
30
|
Args:
|
|
30
31
|
client: The FlashForgeClient instance used for communication with the printer.
|
|
31
32
|
"""
|
|
32
33
|
self.client = client
|
|
33
34
|
|
|
34
|
-
async def get_file_list(self) ->
|
|
35
|
+
async def get_file_list(self) -> list[str]:
|
|
35
36
|
"""
|
|
36
37
|
Retrieves a list of files stored locally on the printer.
|
|
37
|
-
|
|
38
|
+
|
|
38
39
|
Returns:
|
|
39
40
|
A list of file names, or empty list if retrieval fails.
|
|
40
41
|
"""
|
|
41
42
|
# This method uses the TCP client to get file list
|
|
42
|
-
if hasattr(self.client,
|
|
43
|
+
if hasattr(self.client, "tcp_client") and self.client.tcp_client:
|
|
43
44
|
return await self.client.tcp_client.get_file_list_async()
|
|
44
45
|
return []
|
|
45
46
|
|
|
46
|
-
async def get_local_file_list(self) ->
|
|
47
|
+
async def get_local_file_list(self) -> list[str]:
|
|
47
48
|
"""
|
|
48
49
|
Retrieves a list of files stored locally on the printer.
|
|
49
|
-
|
|
50
|
+
|
|
50
51
|
Returns:
|
|
51
52
|
A list of file names, or empty list if retrieval fails.
|
|
52
53
|
"""
|
|
53
54
|
return await self.get_file_list()
|
|
54
55
|
|
|
55
|
-
async def get_recent_file_list(self) ->
|
|
56
|
+
async def get_recent_file_list(self) -> list[FFGcodeFileEntry]:
|
|
56
57
|
"""
|
|
57
58
|
Retrieves a list of the 10 most recently printed files from the printer's API.
|
|
58
59
|
For AD5X and newer printers, returns detailed file entries with material info.
|
|
@@ -61,17 +62,14 @@ class Files:
|
|
|
61
62
|
Returns:
|
|
62
63
|
A list of FFGcodeFileEntry objects. Returns an empty list if the request fails or an error occurs.
|
|
63
64
|
"""
|
|
64
|
-
payload = {
|
|
65
|
-
"serialNumber": self.client.serial_number,
|
|
66
|
-
"checkCode": self.client.check_code
|
|
67
|
-
}
|
|
65
|
+
payload = {"serialNumber": self.client.serial_number, "checkCode": self.client.check_code}
|
|
68
66
|
|
|
69
67
|
try:
|
|
70
68
|
async with aiohttp.ClientSession() as session:
|
|
71
69
|
async with session.post(
|
|
72
70
|
self.client.get_endpoint(Endpoints.GCODE_LIST),
|
|
73
71
|
json=payload,
|
|
74
|
-
headers={"Content-Type": "application/json"}
|
|
72
|
+
headers={"Content-Type": "application/json"},
|
|
75
73
|
) as response:
|
|
76
74
|
if response.status != 200:
|
|
77
75
|
return []
|
|
@@ -84,6 +82,7 @@ class Files:
|
|
|
84
82
|
# Fallback: manually parse as JSON if Content-Type is malformed
|
|
85
83
|
text = await response.text()
|
|
86
84
|
import json
|
|
85
|
+
|
|
87
86
|
data = json.loads(text)
|
|
88
87
|
|
|
89
88
|
if not NetworkUtils.is_ok(data):
|
|
@@ -96,7 +95,7 @@ class Files:
|
|
|
96
95
|
except ValidationError:
|
|
97
96
|
raw_list = data.get("gcodeList", [])
|
|
98
97
|
if isinstance(raw_list, list):
|
|
99
|
-
entries:
|
|
98
|
+
entries: list[FFGcodeFileEntry] = []
|
|
100
99
|
for file_name in raw_list:
|
|
101
100
|
if isinstance(file_name, str):
|
|
102
101
|
entries.append(
|
|
@@ -120,15 +119,17 @@ class Files:
|
|
|
120
119
|
if isinstance(first_item, str):
|
|
121
120
|
# Convert string array to FFGcodeFileEntry objects
|
|
122
121
|
return [
|
|
123
|
-
FFGcodeFileEntry(
|
|
124
|
-
gcodeFileName=file_name,
|
|
125
|
-
printingTime=0
|
|
126
|
-
)
|
|
122
|
+
FFGcodeFileEntry(gcodeFileName=file_name, printingTime=0)
|
|
127
123
|
for file_name in result.gcode_list
|
|
124
|
+
if isinstance(file_name, str)
|
|
125
|
+
]
|
|
126
|
+
elif isinstance(first_item, FFGcodeFileEntry):
|
|
127
|
+
# Already FFGcodeFileEntry objects - need explicit type narrowing
|
|
128
|
+
return [
|
|
129
|
+
item
|
|
130
|
+
for item in result.gcode_list
|
|
131
|
+
if isinstance(item, FFGcodeFileEntry)
|
|
128
132
|
]
|
|
129
|
-
else:
|
|
130
|
-
# Already FFGcodeFileEntry objects
|
|
131
|
-
return result.gcode_list
|
|
132
133
|
|
|
133
134
|
return []
|
|
134
135
|
|
|
@@ -136,7 +137,7 @@ class Files:
|
|
|
136
137
|
print(f"GetRecentFileList error: {err}")
|
|
137
138
|
return []
|
|
138
139
|
|
|
139
|
-
async def get_gcode_thumbnail(self, file_name: str) ->
|
|
140
|
+
async def get_gcode_thumbnail(self, file_name: str) -> bytes | None:
|
|
140
141
|
"""
|
|
141
142
|
Retrieves the thumbnail image for a specified G-code file.
|
|
142
143
|
The image data is returned as bytes.
|
|
@@ -151,7 +152,7 @@ class Files:
|
|
|
151
152
|
payload = {
|
|
152
153
|
"serialNumber": self.client.serial_number,
|
|
153
154
|
"checkCode": self.client.check_code,
|
|
154
|
-
"fileName": file_name
|
|
155
|
+
"fileName": file_name,
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
try:
|
|
@@ -159,7 +160,7 @@ class Files:
|
|
|
159
160
|
async with session.post(
|
|
160
161
|
self.client.get_endpoint(Endpoints.GCODE_THUMB),
|
|
161
162
|
json=payload,
|
|
162
|
-
headers={"Content-Type": "application/json"}
|
|
163
|
+
headers={"Content-Type": "application/json"},
|
|
163
164
|
) as response:
|
|
164
165
|
if response.status != 200:
|
|
165
166
|
return None
|
|
@@ -172,6 +173,7 @@ class Files:
|
|
|
172
173
|
# Fallback: manually parse as JSON if Content-Type is malformed
|
|
173
174
|
text = await response.text()
|
|
174
175
|
import json
|
|
176
|
+
|
|
175
177
|
data = json.loads(text)
|
|
176
178
|
|
|
177
179
|
if NetworkUtils.is_ok(data):
|
flashforge/api/controls/info.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
FlashForge Python API - Info Module
|
|
3
3
|
"""
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
5
7
|
|
|
6
8
|
import aiohttp
|
|
7
9
|
|
|
8
|
-
from ...models.machine_info import FFMachineInfo, MachineState
|
|
9
|
-
from ...models.responses import DetailResponse
|
|
10
|
+
from ...models.machine_info import FFMachineInfo, MachineState, Temperature
|
|
11
|
+
from ...models.responses import DetailResponse, FFPrinterDetail
|
|
10
12
|
from ..constants.endpoints import Endpoints
|
|
11
13
|
|
|
12
14
|
if TYPE_CHECKING:
|
|
@@ -21,13 +23,13 @@ class MachineInfoParser:
|
|
|
21
23
|
"""
|
|
22
24
|
|
|
23
25
|
@staticmethod
|
|
24
|
-
def from_detail(detail) ->
|
|
26
|
+
def from_detail(detail: FFPrinterDetail | None) -> FFMachineInfo | None:
|
|
25
27
|
"""
|
|
26
28
|
Converts printer details from the API response format to our internal FFMachineInfo model.
|
|
27
|
-
|
|
29
|
+
|
|
28
30
|
Args:
|
|
29
31
|
detail: The FFPrinterDetail object received from the printer's API.
|
|
30
|
-
|
|
32
|
+
|
|
31
33
|
Returns:
|
|
32
34
|
An FFMachineInfo object containing structured and formatted printer information,
|
|
33
35
|
or None if the input detail is None or an error occurs during processing.
|
|
@@ -36,42 +38,13 @@ class MachineInfoParser:
|
|
|
36
38
|
return None
|
|
37
39
|
|
|
38
40
|
try:
|
|
39
|
-
# Helper function to format time from seconds
|
|
40
|
-
def format_time_from_seconds(seconds: float) -> str:
|
|
41
|
-
try:
|
|
42
|
-
valid_seconds = int(seconds) if isinstance(seconds, (int, float)) else 0
|
|
43
|
-
hours = valid_seconds // 3600
|
|
44
|
-
minutes = (valid_seconds % 3600) // 60
|
|
45
|
-
return f"{hours:02d}:{minutes:02d}"
|
|
46
|
-
except Exception:
|
|
47
|
-
return "00:00"
|
|
48
|
-
|
|
49
|
-
# Helper function to get machine state
|
|
50
|
-
def get_machine_state(status: str) -> MachineState:
|
|
51
|
-
valid_status = status.lower() if isinstance(status, str) else ""
|
|
52
|
-
state_mapping = {
|
|
53
|
-
"ready": MachineState.READY,
|
|
54
|
-
"busy": MachineState.BUSY,
|
|
55
|
-
"calibrate_doing": MachineState.CALIBRATING,
|
|
56
|
-
"error": MachineState.ERROR,
|
|
57
|
-
"heating": MachineState.HEATING,
|
|
58
|
-
"printing": MachineState.PRINTING,
|
|
59
|
-
"pausing": MachineState.PAUSING,
|
|
60
|
-
"paused": MachineState.PAUSED,
|
|
61
|
-
"cancel": MachineState.CANCELLED,
|
|
62
|
-
"completed": MachineState.COMPLETED,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if valid_status in state_mapping:
|
|
66
|
-
return state_mapping[valid_status]
|
|
67
|
-
|
|
68
|
-
if valid_status:
|
|
69
|
-
print(f"Unknown machine status received: '{status}'")
|
|
70
|
-
return MachineState.UNKNOWN
|
|
71
|
-
|
|
72
41
|
# Calculate derived values
|
|
73
|
-
|
|
74
|
-
|
|
42
|
+
estimated_time = getattr(detail, "estimated_time", 0) or 0
|
|
43
|
+
print_eta = MachineInfoParser._format_time_from_seconds(estimated_time)
|
|
44
|
+
formatted_run_time = MachineInfoParser._format_time_from_seconds(
|
|
45
|
+
getattr(detail, "print_duration", 0) or 0
|
|
46
|
+
)
|
|
47
|
+
completion_time = datetime.now() + timedelta(seconds=estimated_time)
|
|
75
48
|
|
|
76
49
|
total_minutes = getattr(detail, "cumulative_print_time", 0) or 0
|
|
77
50
|
hours = total_minutes // 60
|
|
@@ -90,67 +63,63 @@ class MachineInfoParser:
|
|
|
90
63
|
print_progress = getattr(detail, "print_progress", 0) or 0
|
|
91
64
|
est_length = total_job_filament_meters * print_progress
|
|
92
65
|
est_weight = (getattr(detail, "estimated_right_weight", 0) or 0) * print_progress
|
|
66
|
+
has_material_station = (
|
|
67
|
+
getattr(detail, "has_matl_station", None) is True
|
|
68
|
+
or (getattr(getattr(detail, "matl_station_info", None), "slot_cnt", 0) or 0) > 0
|
|
69
|
+
or len(getattr(getattr(detail, "matl_station_info", None), "slot_infos", []) or []) > 0
|
|
70
|
+
)
|
|
71
|
+
printer_name = getattr(detail, "name", "") or ""
|
|
72
|
+
is_ad5x = printer_name.upper() == "AD5X" or has_material_station
|
|
73
|
+
is_pro = "Pro" in printer_name and not is_ad5x
|
|
93
74
|
|
|
94
75
|
# Build the FFMachineInfo object
|
|
95
76
|
machine_info = FFMachineInfo(
|
|
96
77
|
# Auto-shutdown settings
|
|
97
78
|
auto_shutdown=auto_shutdown,
|
|
98
79
|
auto_shutdown_time=getattr(detail, "auto_shutdown_time", 0) or 0,
|
|
99
|
-
|
|
100
80
|
# Camera
|
|
101
81
|
camera_stream_url=getattr(detail, "camera_stream_url", "") or "",
|
|
102
|
-
|
|
103
82
|
# Fan speeds
|
|
104
83
|
chamber_fan_speed=getattr(detail, "chamber_fan_speed", 0) or 0,
|
|
105
84
|
cooling_fan_speed=getattr(detail, "cooling_fan_speed", 0) or 0,
|
|
106
85
|
cooling_fan_left_speed=getattr(detail, "cooling_fan_left_speed", None),
|
|
107
|
-
|
|
108
86
|
# Cumulative stats
|
|
109
87
|
cumulative_filament=getattr(detail, "cumulative_filament", 0) or 0,
|
|
110
88
|
cumulative_print_time=getattr(detail, "cumulative_print_time", 0) or 0,
|
|
111
|
-
|
|
112
89
|
# Current print speed
|
|
113
90
|
current_print_speed=getattr(detail, "current_print_speed", 0) or 0,
|
|
114
|
-
|
|
115
91
|
# Disk space
|
|
116
92
|
free_disk_space=f"{(getattr(detail, 'remaining_disk_space', 0) or 0):.2f}",
|
|
117
|
-
|
|
118
93
|
# Door and error status
|
|
119
94
|
door_open=door_open,
|
|
120
95
|
error_code=getattr(detail, "error_code", "") or "",
|
|
121
|
-
|
|
122
96
|
# Current print estimates
|
|
123
97
|
est_length=est_length,
|
|
124
98
|
est_weight=est_weight,
|
|
125
99
|
estimated_time=getattr(detail, "estimated_time", 0) or 0,
|
|
126
|
-
|
|
127
100
|
# Fans & LED status
|
|
128
101
|
external_fan_on=external_fan_on,
|
|
129
102
|
internal_fan_on=internal_fan_on,
|
|
130
103
|
lights_on=lights_on,
|
|
131
|
-
|
|
132
104
|
# Network
|
|
133
105
|
ip_address=getattr(detail, "ip_addr", "") or "",
|
|
134
106
|
mac_address=getattr(detail, "mac_addr", "") or "",
|
|
135
|
-
|
|
136
107
|
# Print settings
|
|
137
108
|
fill_amount=getattr(detail, "fill_amount", 0) or 0,
|
|
138
109
|
firmware_version=getattr(detail, "firmware_version", "") or "",
|
|
139
|
-
name=
|
|
140
|
-
is_pro=
|
|
141
|
-
is_ad5x=
|
|
110
|
+
name=printer_name,
|
|
111
|
+
is_pro=is_pro,
|
|
112
|
+
is_ad5x=is_ad5x,
|
|
142
113
|
nozzle_size=getattr(detail, "nozzle_model", "") or "",
|
|
143
|
-
|
|
144
114
|
# Temperatures
|
|
145
|
-
print_bed=
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
extruder=
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
115
|
+
print_bed=Temperature(
|
|
116
|
+
current=getattr(detail, "plat_temp", 0) or 0,
|
|
117
|
+
set=getattr(detail, "plat_target_temp", 0) or 0,
|
|
118
|
+
),
|
|
119
|
+
extruder=Temperature(
|
|
120
|
+
current=getattr(detail, "right_temp", 0) or 0,
|
|
121
|
+
set=getattr(detail, "right_target_temp", 0) or 0,
|
|
122
|
+
),
|
|
154
123
|
# Current print stats
|
|
155
124
|
print_duration=getattr(detail, "print_duration", 0) or 0,
|
|
156
125
|
print_file_name=getattr(detail, "print_file_name", "") or "",
|
|
@@ -160,23 +129,20 @@ class MachineInfoParser:
|
|
|
160
129
|
print_progress_int=int(print_progress * 100),
|
|
161
130
|
print_speed_adjust=getattr(detail, "print_speed_adjust", 0) or 0,
|
|
162
131
|
filament_type=getattr(detail, "right_filament_type", "") or "",
|
|
163
|
-
|
|
164
132
|
# Machine state
|
|
165
|
-
machine_state=
|
|
133
|
+
machine_state=MachineInfoParser._get_machine_state(getattr(detail, "status", "") or ""),
|
|
166
134
|
status=getattr(detail, "status", "") or "",
|
|
167
135
|
total_print_layers=getattr(detail, "target_print_layer", 0) or 0,
|
|
168
136
|
tvoc=getattr(detail, "tvoc", 0) or 0,
|
|
169
137
|
z_axis_compensation=getattr(detail, "z_axis_compensation", 0) or 0,
|
|
170
|
-
|
|
171
138
|
# Cloud codes
|
|
172
139
|
flash_cloud_register_code=getattr(detail, "flash_register_code", "") or "",
|
|
173
140
|
polar_cloud_register_code=getattr(detail, "polar_register_code", "") or "",
|
|
174
|
-
|
|
175
141
|
# Extras
|
|
176
142
|
print_eta=print_eta,
|
|
143
|
+
completion_time=completion_time,
|
|
177
144
|
formatted_run_time=formatted_run_time,
|
|
178
145
|
formatted_total_run_time=formatted_total_run_time,
|
|
179
|
-
|
|
180
146
|
# AD5X Material Station
|
|
181
147
|
has_matl_station=getattr(detail, "has_matl_station", None),
|
|
182
148
|
matl_station_info=getattr(detail, "matl_station_info", None),
|
|
@@ -190,6 +156,41 @@ class MachineInfoParser:
|
|
|
190
156
|
print(f"Detail object causing error: {detail}")
|
|
191
157
|
return None
|
|
192
158
|
|
|
159
|
+
@staticmethod
|
|
160
|
+
def _format_time_from_seconds(seconds: float) -> str:
|
|
161
|
+
"""Format a duration in seconds as HH:MM."""
|
|
162
|
+
try:
|
|
163
|
+
valid_seconds = int(seconds) if isinstance(seconds, (int, float)) else 0
|
|
164
|
+
hours = valid_seconds // 3600
|
|
165
|
+
minutes = (valid_seconds % 3600) // 60
|
|
166
|
+
return f"{hours:02d}:{minutes:02d}"
|
|
167
|
+
except Exception:
|
|
168
|
+
return "00:00"
|
|
169
|
+
|
|
170
|
+
@staticmethod
|
|
171
|
+
def _get_machine_state(status: str) -> MachineState:
|
|
172
|
+
"""Map raw status strings into the public machine state enum."""
|
|
173
|
+
valid_status = status.lower() if isinstance(status, str) else ""
|
|
174
|
+
state_mapping = {
|
|
175
|
+
"ready": MachineState.READY,
|
|
176
|
+
"busy": MachineState.BUSY,
|
|
177
|
+
"calibrate_doing": MachineState.CALIBRATING,
|
|
178
|
+
"error": MachineState.ERROR,
|
|
179
|
+
"heating": MachineState.HEATING,
|
|
180
|
+
"printing": MachineState.PRINTING,
|
|
181
|
+
"pausing": MachineState.PAUSING,
|
|
182
|
+
"paused": MachineState.PAUSED,
|
|
183
|
+
"cancel": MachineState.CANCELLED,
|
|
184
|
+
"completed": MachineState.COMPLETED,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if valid_status in state_mapping:
|
|
188
|
+
return state_mapping[valid_status]
|
|
189
|
+
|
|
190
|
+
if valid_status:
|
|
191
|
+
print(f"Unknown machine status received: '{status}'")
|
|
192
|
+
return MachineState.UNKNOWN
|
|
193
|
+
|
|
193
194
|
|
|
194
195
|
class Info:
|
|
195
196
|
"""
|
|
@@ -200,17 +201,17 @@ class Info:
|
|
|
200
201
|
def __init__(self, client: "FlashForgeClient"):
|
|
201
202
|
"""
|
|
202
203
|
Creates an instance of the Info class.
|
|
203
|
-
|
|
204
|
+
|
|
204
205
|
Args:
|
|
205
206
|
client: The FlashForgeClient instance used for communication with the printer.
|
|
206
207
|
"""
|
|
207
208
|
self.client = client
|
|
208
209
|
|
|
209
|
-
async def get(self) ->
|
|
210
|
+
async def get(self) -> FFMachineInfo | None:
|
|
210
211
|
"""
|
|
211
212
|
Retrieves comprehensive machine information, processed into the FFMachineInfo model.
|
|
212
213
|
This method fetches detailed data from the printer and transforms it.
|
|
213
|
-
|
|
214
|
+
|
|
214
215
|
Returns:
|
|
215
216
|
An FFMachineInfo object, or None if an error occurs or no data is returned.
|
|
216
217
|
"""
|
|
@@ -222,53 +223,50 @@ class Info:
|
|
|
222
223
|
async def is_printing(self) -> bool:
|
|
223
224
|
"""
|
|
224
225
|
Checks if the printer is currently in the "printing" state.
|
|
225
|
-
|
|
226
|
+
|
|
226
227
|
Returns:
|
|
227
228
|
True if the printer is printing, False otherwise or if status cannot be determined.
|
|
228
229
|
"""
|
|
229
230
|
info = await self.get()
|
|
230
231
|
return info.status == "printing" if info else False
|
|
231
232
|
|
|
232
|
-
async def get_status(self) ->
|
|
233
|
+
async def get_status(self) -> str | None:
|
|
233
234
|
"""
|
|
234
235
|
Retrieves the raw status string of the printer (e.g., "ready", "printing", "error").
|
|
235
|
-
|
|
236
|
+
|
|
236
237
|
Returns:
|
|
237
238
|
The status string, or None if it cannot be determined.
|
|
238
239
|
"""
|
|
239
240
|
info = await self.get()
|
|
240
241
|
return info.status if info else None
|
|
241
242
|
|
|
242
|
-
async def get_machine_state(self) ->
|
|
243
|
+
async def get_machine_state(self) -> MachineState | None:
|
|
243
244
|
"""
|
|
244
245
|
Retrieves the machine state as a MachineState enum value.
|
|
245
|
-
|
|
246
|
+
|
|
246
247
|
Returns:
|
|
247
248
|
A MachineState enum value, or None if it cannot be determined.
|
|
248
249
|
"""
|
|
249
250
|
info = await self.get()
|
|
250
251
|
return info.machine_state if info else None
|
|
251
252
|
|
|
252
|
-
async def get_detail_response(self) ->
|
|
253
|
+
async def get_detail_response(self) -> DetailResponse | None:
|
|
253
254
|
"""
|
|
254
255
|
Retrieves the raw detailed response from the printer's detail endpoint.
|
|
255
256
|
This contains a wealth of information about the printer's current state.
|
|
256
|
-
|
|
257
|
+
|
|
257
258
|
Returns:
|
|
258
259
|
A DetailResponse object containing the raw printer details,
|
|
259
260
|
or None if the request fails or an error occurs.
|
|
260
261
|
"""
|
|
261
|
-
payload = {
|
|
262
|
-
"serialNumber": self.client.serial_number,
|
|
263
|
-
"checkCode": self.client.check_code
|
|
264
|
-
}
|
|
262
|
+
payload = {"serialNumber": self.client.serial_number, "checkCode": self.client.check_code}
|
|
265
263
|
|
|
266
264
|
try:
|
|
267
265
|
async with aiohttp.ClientSession() as session:
|
|
268
266
|
async with session.post(
|
|
269
267
|
self.client.get_endpoint(Endpoints.DETAIL),
|
|
270
268
|
json=payload,
|
|
271
|
-
headers={"Content-Type": "application/json"}
|
|
269
|
+
headers={"Content-Type": "application/json"},
|
|
272
270
|
) as response:
|
|
273
271
|
if response.status != 200:
|
|
274
272
|
print(f"Non-200 status from detail endpoint: {response.status}")
|
|
@@ -283,8 +281,9 @@ class Info:
|
|
|
283
281
|
# Fallback: manually parse as JSON if Content-Type is malformed
|
|
284
282
|
text = await response.text()
|
|
285
283
|
import json
|
|
284
|
+
|
|
286
285
|
data = json.loads(text)
|
|
287
|
-
|
|
286
|
+
|
|
288
287
|
return DetailResponse(**data)
|
|
289
288
|
|
|
290
289
|
except Exception as error:
|