anycubic-cloud-api 0.1.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.
Files changed (33) hide show
  1. anycubic_cloud_api/__init__.py +62 -0
  2. anycubic_cloud_api/anycubic_api.py +7 -0
  3. anycubic_cloud_api/api/base.py +400 -0
  4. anycubic_cloud_api/api/functions.py +2055 -0
  5. anycubic_cloud_api/api/mqtt.py +449 -0
  6. anycubic_cloud_api/const/api_endpoints.py +106 -0
  7. anycubic_cloud_api/const/const.py +47 -0
  8. anycubic_cloud_api/const/enums.py +97 -0
  9. anycubic_cloud_api/const/mqtt.py +13 -0
  10. anycubic_cloud_api/data_models/consumable.py +116 -0
  11. anycubic_cloud_api/data_models/files.py +429 -0
  12. anycubic_cloud_api/data_models/gcode_file.py +107 -0
  13. anycubic_cloud_api/data_models/orders.py +369 -0
  14. anycubic_cloud_api/data_models/print_response.py +71 -0
  15. anycubic_cloud_api/data_models/print_speed_mode.py +61 -0
  16. anycubic_cloud_api/data_models/printer.py +2753 -0
  17. anycubic_cloud_api/data_models/printer_properties.py +1107 -0
  18. anycubic_cloud_api/data_models/printing_settings.py +130 -0
  19. anycubic_cloud_api/data_models/project.py +1234 -0
  20. anycubic_cloud_api/exceptions/error_strings.py +340 -0
  21. anycubic_cloud_api/exceptions/exceptions.py +91 -0
  22. anycubic_cloud_api/helpers/helpers.py +240 -0
  23. anycubic_cloud_api/models/auth.py +396 -0
  24. anycubic_cloud_api/models/cloud_upload.py +249 -0
  25. anycubic_cloud_api/models/http.py +29 -0
  26. anycubic_cloud_api/resources/anycubic_mqqt_tls_ca.crt +24 -0
  27. anycubic_cloud_api/resources/anycubic_mqqt_tls_client.crt +24 -0
  28. anycubic_cloud_api/resources/anycubic_mqqt_tls_client.key +28 -0
  29. anycubic_cloud_api-0.1.0.dist-info/METADATA +79 -0
  30. anycubic_cloud_api-0.1.0.dist-info/RECORD +33 -0
  31. anycubic_cloud_api-0.1.0.dist-info/WHEEL +5 -0
  32. anycubic_cloud_api-0.1.0.dist-info/licenses/LICENSE +674 -0
  33. anycubic_cloud_api-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2753 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from ..const.enums import (
7
+ AnycubicFunctionID,
8
+ AnycubicPrinterMaterialType,
9
+ AnycubicPrintStatus,
10
+ )
11
+ from ..exceptions.error_strings import (
12
+ ErrorsDataParsing,
13
+ ErrorsGeneral,
14
+ ErrorsMQTTUpdate,
15
+ )
16
+ from ..exceptions.exceptions import (
17
+ AnycubicAPIError,
18
+ AnycubicDataParsingError,
19
+ AnycubicMQTTUnhandledData,
20
+ AnycubicMQTTUnknownUpdate,
21
+ )
22
+ from ..helpers.helpers import (
23
+ get_part_from_mqtt_topic,
24
+ time_duration_string_to_delta,
25
+ timedelta_to_dhm_string,
26
+ timedelta_to_total_hours,
27
+ )
28
+ from .consumable import AnycubicConsumableData
29
+ from .files import AnycubicFile
30
+ from .printer_properties import (
31
+ AnycubicMachineColorInfo,
32
+ AnycubicMachineData,
33
+ AnycubicMachineExternalShelves,
34
+ AnycubicMachineFirmwareInfo,
35
+ AnycubicMachineParameter,
36
+ AnycubicMachineToolInfo,
37
+ AnycubicMaterialColor,
38
+ AnycubicMultiColorBox,
39
+ )
40
+ from .printing_settings import AnycubicPrintingSettings
41
+ from .project import AnycubicProject
42
+
43
+ if TYPE_CHECKING:
44
+ from datetime import timedelta
45
+
46
+ from ..anycubic_api import AnycubicAPI
47
+ from .print_response import AnycubicPrintResponse
48
+ from .printer_properties import AnycubicDryingStatus, AnycubicMaterialMapping
49
+
50
+
51
+ class AnycubicPrinter:
52
+ __slots__ = (
53
+ "_ignore_init_errors",
54
+ "_initialisation_error",
55
+ "_api_parent",
56
+ "_machine_type",
57
+ "_machine_name",
58
+ "_machine_img",
59
+ "_net_function_ids",
60
+ "_net_default_function",
61
+ "_id",
62
+ "_user_id",
63
+ "_name",
64
+ "_nonce",
65
+ "_key",
66
+ "_user_img",
67
+ "_description",
68
+ "_printer_type",
69
+ "_device_status",
70
+ "_ready_status",
71
+ "_is_printing",
72
+ "_reason",
73
+ "_video_taskid",
74
+ "_msg",
75
+ "_material_used",
76
+ "_total_print_time",
77
+ "_total_print_time_delta",
78
+ "_total_print_time_hrs",
79
+ "_total_print_time_dhm_str",
80
+ "_print_count",
81
+ "_status",
82
+ "_machine_mac",
83
+ "_delete",
84
+ "_create_time",
85
+ "_delete_time",
86
+ "_last_update_time",
87
+ "_machine_data",
88
+ "_type_function_ids",
89
+ "_material_type",
90
+ "_parameter",
91
+ "_fw_version",
92
+ "_available",
93
+ "_color",
94
+ "_advance",
95
+ "_tools",
96
+ "_multi_color_box_fw_version",
97
+ "_external_shelves",
98
+ "_multi_color_box",
99
+ "_latest_project",
100
+ "_fan_speed",
101
+ "_aux_fan_speed",
102
+ "_box_fan_level",
103
+ "_print_speed_pct",
104
+ "_print_speed_mode",
105
+ "_local_file_list",
106
+ "_udisk_file_list",
107
+ "_has_peripheral_camera",
108
+ "_has_peripheral_multi_color_box",
109
+ "_has_peripheral_udisk",
110
+ "_is_bound_to_user",
111
+ "_job_download_progress",
112
+ "_lights",
113
+ )
114
+
115
+ def __init__(
116
+ self,
117
+ api_parent: AnycubicAPI,
118
+ machine_type: int,
119
+ machine_name: str,
120
+ machine_img: str | None = None,
121
+ net_function_ids: list[int] | None = None,
122
+ net_default_function: int | None = None,
123
+ id: int | None = None,
124
+ user_id: int | None = None,
125
+ name: str | None = None,
126
+ nonce: str | int | None = None,
127
+ key: str | None = None,
128
+ user_img: str | None = None,
129
+ description: str | None = None,
130
+ printer_type: str | None = None,
131
+ device_status: int | None = None,
132
+ ready_status: int | None = None,
133
+ is_printing: int | None = None,
134
+ reason: str | None = None,
135
+ video_taskid: int | None = None,
136
+ msg: str | None = None,
137
+ material_used: str | None = None,
138
+ print_totaltime: str | None = None,
139
+ print_count: int | None = None,
140
+ status: int | None = None,
141
+ machine_mac: str | None = None,
142
+ delete: int | None = None,
143
+ create_time: int | None = None,
144
+ delete_time: int | None = None,
145
+ last_update_time: int | None = None,
146
+ machine_data: dict[str, Any] | None = None,
147
+ type_function_ids: list[int] | None = None,
148
+ material_type: str | None = None,
149
+ parameter: dict[str, Any] | None = None,
150
+ fw_version: dict[str, Any] | None = None,
151
+ available: int | None = None,
152
+ color: list[list[int]] | None = None,
153
+ advance: list[Any] | None = None,
154
+ tools: list[dict[str, Any]] | None = None,
155
+ multi_color_box_fw_version: list[dict[str, Any]] | None = None,
156
+ external_shelves: dict[str, Any] | None = None,
157
+ multi_color_box: list[dict[str, Any]] | dict[str, Any] | None = None,
158
+ ignore_init_errors: bool = False,
159
+ # base_info=None,
160
+ ) -> None:
161
+ self._ignore_init_errors: bool = ignore_init_errors
162
+ self._initialisation_error: bool = False
163
+
164
+ self._api_parent: AnycubicAPI = api_parent
165
+ self._machine_type = machine_type
166
+ self._machine_name = machine_name
167
+ self._machine_img = machine_img
168
+ self._net_function_ids = net_function_ids
169
+ self._net_default_function = net_default_function
170
+ self._id = id
171
+ self._user_id = user_id
172
+ self._name = name
173
+ self._nonce = nonce
174
+ self._key = key
175
+ self._user_img = user_img
176
+ self._description = description
177
+ self._printer_type = printer_type
178
+ self._device_status = device_status
179
+ self._ready_status = ready_status
180
+ self._is_printing: int = int(is_printing) if is_printing is not None else 1
181
+ self._reason = reason
182
+ self._video_taskid = video_taskid
183
+ self._msg = msg
184
+ self._material_used = material_used
185
+ self._set_total_print_time(print_totaltime)
186
+ self._print_count = print_count
187
+ self._status = status
188
+ self._machine_mac = machine_mac
189
+ self._delete = delete
190
+ self._create_time = create_time
191
+ self._delete_time = delete_time
192
+ self._last_update_time = last_update_time
193
+ self._set_machine_data(machine_data)
194
+ self._set_type_function_ids(type_function_ids)
195
+ self._set_material_type(material_type)
196
+ self._set_parameter(parameter)
197
+ self._set_fw_version(fw_version)
198
+ self._available = available
199
+ self._set_color(color)
200
+ self._advance = advance
201
+ self._set_tools(tools)
202
+ self._set_multi_color_box_fw_version(multi_color_box_fw_version)
203
+ self._set_external_shelves(external_shelves)
204
+ self._set_multi_color_box(multi_color_box)
205
+
206
+ self._latest_project: AnycubicProject | None = None
207
+ self._fan_speed: int = 0
208
+ self._print_speed_pct: int = 0
209
+ self._print_speed_mode: int = 0
210
+ self._local_file_list: list[AnycubicFile] | None = None
211
+ self._udisk_file_list: list[AnycubicFile] | None = None
212
+ self._has_peripheral_camera: bool = False
213
+ self._has_peripheral_multi_color_box: bool = False
214
+ self._has_peripheral_udisk: bool = False
215
+ self._is_bound_to_user: bool = True
216
+ self._job_download_progress: int = 0
217
+ self._aux_fan_speed: int | None = None
218
+ self._box_fan_level: int | None = None
219
+ # Keyed by the light `type` the printer reports (Kobra S1 uses 2).
220
+ self._lights: dict[int, dict[str, int]] = dict()
221
+
222
+ self._ignore_init_errors = False
223
+
224
+ def _set_job_download_progress(self, job_download_progress: int | None) -> None:
225
+ self._job_download_progress = int(job_download_progress) if job_download_progress is not None else 0
226
+
227
+ def _set_total_print_time(self, print_totaltime: str | None) -> None:
228
+ self._total_print_time: str | None = print_totaltime
229
+ self._total_print_time_delta: timedelta = time_duration_string_to_delta(print_totaltime)
230
+ self._total_print_time_hrs: int = int(timedelta_to_total_hours(self._total_print_time_delta))
231
+ self._total_print_time_dhm_str: str = timedelta_to_dhm_string(self._total_print_time_delta)
232
+
233
+ def set_has_peripheral_camera(self, has_peripheral: bool) -> None:
234
+ self._has_peripheral_camera = bool(has_peripheral)
235
+
236
+ def set_has_peripheral_multi_color_box(self, has_peripheral: bool) -> None:
237
+ self._has_peripheral_multi_color_box = bool(has_peripheral)
238
+
239
+ def set_has_peripheral_udisk(self, has_peripheral: bool) -> None:
240
+ self._has_peripheral_udisk = bool(has_peripheral)
241
+
242
+ def _set_type_function_ids(self, type_function_ids: list[int] | None) -> None:
243
+ if isinstance(type_function_ids, list):
244
+ self._type_function_ids = type_function_ids
245
+ else:
246
+ self._type_function_ids = list()
247
+
248
+ def _set_material_type(self, material_type: str | None) -> None:
249
+ self._material_type: AnycubicPrinterMaterialType | str | None = None
250
+
251
+ if material_type and isinstance(material_type, str):
252
+ try:
253
+ self._material_type = AnycubicPrinterMaterialType(material_type.title())
254
+
255
+ except ValueError:
256
+ self._material_type = material_type
257
+
258
+ def _set_local_file_list(self, file_list: list[dict[str, Any]] | None) -> None:
259
+ if file_list is None:
260
+ return
261
+
262
+ self._local_file_list = list()
263
+ for x in file_list:
264
+ file = AnycubicFile.from_json(x)
265
+ if file:
266
+ self._local_file_list.append(file)
267
+ else:
268
+ raise AnycubicDataParsingError(ErrorsDataParsing.local_file_list.format(file_list))
269
+
270
+ def _set_udisk_file_list(self, file_list: list[dict[str, Any]] | None) -> None:
271
+ if file_list is None:
272
+ return
273
+
274
+ self._udisk_file_list = list()
275
+ for x in file_list:
276
+ file = AnycubicFile.from_json(x)
277
+ if file:
278
+ self._udisk_file_list.append(file)
279
+ else:
280
+ raise AnycubicDataParsingError(ErrorsDataParsing.udisk_file_list.format(file_list))
281
+
282
+ def _set_multi_color_box(self, multi_color_box: list[dict[str, Any]] | dict[str, Any] | None) -> None:
283
+ self._multi_color_box: list[AnycubicMultiColorBox] | None = None
284
+ try:
285
+ if multi_color_box is None or isinstance(multi_color_box, list):
286
+ multi_color_box_list = multi_color_box
287
+ else:
288
+ multi_color_box_list = list([multi_color_box])
289
+ if multi_color_box_list is not None:
290
+ self._multi_color_box = list()
291
+ for x in multi_color_box_list:
292
+ ace = AnycubicMultiColorBox.from_json(x)
293
+ if ace:
294
+ self._multi_color_box.append(ace)
295
+ else:
296
+ raise AnycubicDataParsingError(ErrorsDataParsing.ace.format(multi_color_box))
297
+
298
+ except Exception as e:
299
+ self._initialisation_error = True
300
+ if not self._ignore_init_errors:
301
+ raise e
302
+
303
+ def _set_machine_data(
304
+ self,
305
+ machine_data: dict[str, Any] | None,
306
+ ) -> None:
307
+ try:
308
+ self._machine_data = AnycubicMachineData.from_json(machine_data)
309
+ except Exception as e:
310
+ self._initialisation_error = True
311
+ if not self._ignore_init_errors:
312
+ raise e
313
+
314
+ def _set_parameter(
315
+ self,
316
+ parameter: dict[str, Any] | None,
317
+ ) -> None:
318
+ try:
319
+ self._parameter = AnycubicMachineParameter.from_json(parameter)
320
+ except Exception as e:
321
+ self._initialisation_error = True
322
+ if not self._ignore_init_errors:
323
+ raise e
324
+
325
+ def _set_fw_version(
326
+ self,
327
+ fw_version: dict[str, Any] | None,
328
+ ) -> None:
329
+ try:
330
+ self._fw_version = AnycubicMachineFirmwareInfo.from_json(fw_version)
331
+ except Exception as e:
332
+ self._initialisation_error = True
333
+ if not self._ignore_init_errors:
334
+ raise e
335
+
336
+ def _set_color(
337
+ self,
338
+ color: list[list[int]] | None,
339
+ ) -> None:
340
+ try:
341
+ self._color = AnycubicMachineColorInfo.from_json(color)
342
+ except Exception as e:
343
+ self._initialisation_error = True
344
+ if not self._ignore_init_errors:
345
+ raise e
346
+
347
+ def _set_tools(
348
+ self,
349
+ tools: list[dict[str, Any]] | None,
350
+ ) -> None:
351
+ self._tools: list[AnycubicMachineToolInfo] | None = None
352
+ try:
353
+ if tools is not None:
354
+ self._tools = list()
355
+ for x in tools:
356
+ tool = AnycubicMachineToolInfo.from_json(x)
357
+ if tool:
358
+ self._tools.append(tool)
359
+ else:
360
+ raise AnycubicDataParsingError(ErrorsDataParsing.tools.format(tools))
361
+ except Exception as e:
362
+ self._initialisation_error = True
363
+ if not self._ignore_init_errors:
364
+ raise e
365
+
366
+ def _set_multi_color_box_fw_version(
367
+ self,
368
+ multi_color_box_fw_version: list[dict[str, Any]] | None,
369
+ ) -> None:
370
+ self._multi_color_box_fw_version: list[AnycubicMachineFirmwareInfo] | None = None
371
+ try:
372
+ if multi_color_box_fw_version is not None:
373
+ self._multi_color_box_fw_version = list()
374
+ for x in multi_color_box_fw_version:
375
+ ace = AnycubicMachineFirmwareInfo.from_json(x)
376
+ if ace:
377
+ self._multi_color_box_fw_version.append(ace)
378
+ else:
379
+ raise AnycubicDataParsingError(
380
+ ErrorsDataParsing.ace_fw_version.format(multi_color_box_fw_version)
381
+ )
382
+ except Exception as e:
383
+ self._initialisation_error = True
384
+ if not self._ignore_init_errors:
385
+ raise e
386
+
387
+ def _set_external_shelves(
388
+ self,
389
+ external_shelves: dict[str, Any] | None,
390
+ ) -> None:
391
+ try:
392
+ self._external_shelves = AnycubicMachineExternalShelves.from_json(external_shelves)
393
+ except Exception as e:
394
+ self._initialisation_error = True
395
+ if not self._ignore_init_errors:
396
+ raise e
397
+
398
+ def _update_fw_version_from_json(
399
+ self,
400
+ fw_version: dict[str, Any] | None,
401
+ ) -> None:
402
+ if fw_version is None:
403
+ return
404
+
405
+ if self._fw_version:
406
+ self._fw_version.update_from_json(fw_version)
407
+ else:
408
+ self._set_fw_version(fw_version)
409
+
410
+ def _update_multi_color_box_fw_version_from_json(
411
+ self,
412
+ multi_color_box_fw_version: list[dict[str, Any]] | None,
413
+ ) -> None:
414
+ if (
415
+ multi_color_box_fw_version is None or
416
+ not isinstance(multi_color_box_fw_version, list) or
417
+ len(multi_color_box_fw_version) < 1
418
+ ):
419
+ return
420
+
421
+ if self._multi_color_box_fw_version and len(self._multi_color_box_fw_version) > 0:
422
+ for x, fwver in enumerate(self._multi_color_box_fw_version):
423
+ if fwver and len(multi_color_box_fw_version) >= x + 1:
424
+ fwver.update_from_json(multi_color_box_fw_version[x])
425
+ else:
426
+ self._set_multi_color_box_fw_version(multi_color_box_fw_version)
427
+
428
+ @classmethod
429
+ def from_basic_json(
430
+ cls,
431
+ api_parent: AnycubicAPI,
432
+ data: dict[str, Any],
433
+ ) -> AnycubicPrinter:
434
+ return cls(
435
+ api_parent=api_parent,
436
+ machine_type=data['machine_type'],
437
+ machine_name=data['name'],
438
+ machine_img=data['img'],
439
+ net_function_ids=data['net_function_ids'],
440
+ net_default_function=data['net_default_function'],
441
+ )
442
+
443
+ @classmethod
444
+ def from_status_json(
445
+ cls,
446
+ api_parent: AnycubicAPI,
447
+ data: dict[str, Any],
448
+ ignore_init_errors: bool = False,
449
+ ) -> AnycubicPrinter:
450
+ return cls(
451
+ api_parent=api_parent,
452
+ id=data['id'],
453
+ user_id=data['user_id'],
454
+ name=data['name'],
455
+ nonce=data['nonce'],
456
+ key=data['key'],
457
+ machine_type=data['machine_type'],
458
+ machine_name=data['model'],
459
+ user_img=data.get('img'),
460
+ description=data.get('description'),
461
+ printer_type=data['type'],
462
+ device_status=data['device_status'],
463
+ ready_status=data['ready_status'],
464
+ is_printing=data['is_printing'],
465
+ reason=data.get('reason'),
466
+ video_taskid=data.get('video_taskid'),
467
+ msg=data.get('msg'),
468
+ material_used=data.get('material_used'),
469
+ print_totaltime=data.get('print_totaltime'),
470
+ status=data['status'],
471
+ machine_mac=data.get('machine_mac'),
472
+ delete=data['delete'],
473
+ create_time=data.get('create_time'),
474
+ delete_time=data['delete_time'],
475
+ last_update_time=data['last_update_time'],
476
+ machine_data=data['machine_data'],
477
+ type_function_ids=data['type_function_ids'],
478
+ material_type=data.get('material_type'),
479
+ parameter=data.get('parameter'),
480
+ fw_version=data['version'],
481
+ available=data.get('available'),
482
+ color=data.get('color'),
483
+ ignore_init_errors=ignore_init_errors,
484
+ )
485
+
486
+ @classmethod
487
+ def from_info_json(
488
+ cls,
489
+ api_parent: AnycubicAPI,
490
+ data: dict[str, Any],
491
+ ignore_init_errors: bool = False,
492
+ ) -> AnycubicPrinter:
493
+ try:
494
+ extra_data = data.get('base', {})
495
+ return cls(
496
+ api_parent=api_parent,
497
+ id=data['id'],
498
+ name=data['name'],
499
+ key=data['key'],
500
+ machine_type=data['machine_type'],
501
+ machine_name=data['model'],
502
+ user_img=data.get('img'),
503
+ description=extra_data.get('description'),
504
+ device_status=data['device_status'],
505
+ is_printing=data['is_printing'],
506
+ material_used=extra_data.get('material_used'),
507
+ print_totaltime=extra_data.get('print_totaltime'),
508
+ print_count=extra_data.get('print_count'),
509
+ machine_mac=extra_data.get('machine_mac'),
510
+ create_time=extra_data.get('create_time'),
511
+ machine_data=data.get('machine_data'),
512
+ type_function_ids=data['type_function_ids'],
513
+ material_type=extra_data.get('material_type'),
514
+ parameter=data.get('parameter'),
515
+ fw_version=data['version'],
516
+ tools=data.get('tools'),
517
+ multi_color_box_fw_version=data.get('multi_color_box_version'),
518
+ external_shelves=data.get('external_shelves'),
519
+ multi_color_box=data.get('multi_color_box'),
520
+ ignore_init_errors=ignore_init_errors,
521
+ )
522
+ except Exception as e:
523
+ print(data)
524
+ raise e
525
+
526
+ def update_from_info_json(self, data: dict[str, Any] | None) -> None:
527
+ if data is None:
528
+ return
529
+
530
+ if str(self._id) != str(data['id']):
531
+ return
532
+
533
+ extra_data = data.get('base', {})
534
+
535
+ self._name = data['name']
536
+ self._key = data['key']
537
+ self._machine_type = data['machine_type']
538
+ self._machine_name = data['model']
539
+ self._user_img = data['img']
540
+ self._description = extra_data.get('description')
541
+ self._device_status = data['device_status']
542
+ self._is_printing = data['is_printing']
543
+ self._material_used = extra_data.get('material_used')
544
+ self._set_total_print_time(extra_data.get('print_totaltime'))
545
+ self._print_count = extra_data.get('print_count')
546
+ self._machine_mac = extra_data.get('machine_mac')
547
+ self._create_time = extra_data.get('create_time')
548
+ self._set_machine_data(data.get('machine_data'))
549
+ self._set_type_function_ids(data['type_function_ids'])
550
+ self._set_material_type(extra_data.get('material_type'))
551
+ self._set_parameter(data.get('parameter'))
552
+ self._update_fw_version_from_json(data['version'])
553
+ self._set_tools(data.get('tools'))
554
+ self._update_multi_color_box_fw_version_from_json(data.get('multi_color_box_version'))
555
+ self._set_external_shelves(data.get('external_shelves'))
556
+ self._set_multi_color_box(data.get('multi_color_box'))
557
+
558
+ def _check_latest_project_id_valid(
559
+ self,
560
+ incoming_project_id: int,
561
+ ) -> bool:
562
+ try:
563
+ project_id = int(incoming_project_id)
564
+ except Exception:
565
+ project_id = -1
566
+
567
+ return (
568
+ self._latest_project is not None
569
+ and (
570
+ project_id < 0
571
+ or project_id == self._latest_project.id
572
+ )
573
+ )
574
+
575
+ def _update_latest_project_with_mqtt_print_status_data(
576
+ self,
577
+ incoming_project_id: int,
578
+ print_status: AnycubicPrintStatus,
579
+ mqtt_data: AnycubicConsumableData | None = None,
580
+ paused: int | None = None,
581
+ reason: str | None = None,
582
+ ) -> bool:
583
+ self._set_job_download_progress(0)
584
+
585
+ if self._check_latest_project_id_valid(incoming_project_id):
586
+ assert self._latest_project
587
+ self._latest_project.update_with_mqtt_print_status_data(
588
+ print_status,
589
+ mqtt_data,
590
+ paused=paused,
591
+ reason=reason,
592
+ )
593
+
594
+ return True
595
+
596
+ elif mqtt_data:
597
+ mqtt_data.force_empty()
598
+
599
+ return False
600
+
601
+ def _update_latest_project_with_mqtt_download_status_data(
602
+ self,
603
+ incoming_project_id: int,
604
+ mqtt_data: AnycubicConsumableData,
605
+ ) -> bool:
606
+ self._set_job_download_progress(int(mqtt_data['progress']))
607
+
608
+ if self._check_latest_project_id_valid(incoming_project_id):
609
+ assert self._latest_project
610
+ self._latest_project.update_with_mqtt_download_status_data(
611
+ mqtt_data,
612
+ )
613
+
614
+ return True
615
+
616
+ return False
617
+
618
+ def _update_latest_project_with_mqtt_checking_status_data(
619
+ self,
620
+ incoming_project_id: int,
621
+ ) -> bool:
622
+ self._set_job_download_progress(0)
623
+
624
+ if self._check_latest_project_id_valid(incoming_project_id):
625
+ assert self._latest_project
626
+ self._latest_project.update_with_mqtt_checking_status_data()
627
+
628
+ return True
629
+
630
+ return False
631
+
632
+ def _update_latest_project_slice_param(
633
+ self,
634
+ incoming_project_id: int,
635
+ new_slice_param: str | dict[str, Any] | None,
636
+ ) -> bool:
637
+ if self._check_latest_project_id_valid(incoming_project_id):
638
+ assert self._latest_project
639
+ self._latest_project.set_slice_param(
640
+ new_slice_param,
641
+ )
642
+
643
+ return True
644
+
645
+ return False
646
+
647
+ def _update_latest_project_target_temps(
648
+ self,
649
+ incoming_project_id: int,
650
+ new_target_hotbed_temp: int,
651
+ new_target_nozzle_temp: int,
652
+ ) -> bool:
653
+ if self._check_latest_project_id_valid(incoming_project_id):
654
+ assert self._latest_project
655
+ self._latest_project.update_target_temps(
656
+ new_target_hotbed_temp,
657
+ new_target_nozzle_temp,
658
+ )
659
+
660
+ return True
661
+
662
+ return False
663
+
664
+ def _process_mqtt_update_lastwill(
665
+ self,
666
+ action: str,
667
+ state: str,
668
+ payload: AnycubicConsumableData,
669
+ ) -> None:
670
+ if action == 'onlineReport' and state == 'online':
671
+ self._device_status = 1
672
+ return
673
+ elif action == 'onlineReport' and state == 'offline':
674
+ self._device_status = 2
675
+ return
676
+ else:
677
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.lastwill)
678
+
679
+ def _process_mqtt_update_user(
680
+ self,
681
+ action: str,
682
+ state: str,
683
+ payload: AnycubicConsumableData,
684
+ ) -> None:
685
+ if action == 'bindQuery' and state == 'done':
686
+ self._is_bound_to_user = True
687
+ return
688
+ elif action == 'unbind' and state == 'done':
689
+ self._is_bound_to_user = False
690
+ return
691
+ else:
692
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.user)
693
+
694
+ def _process_mqtt_update_status(
695
+ self,
696
+ action: str,
697
+ state: str,
698
+ payload: AnycubicConsumableData,
699
+ ) -> None:
700
+ if action == 'workReport' and state == 'free':
701
+ self._is_printing = 1
702
+ return
703
+ elif action == 'workReport' and state == 'busy':
704
+ self._is_printing = 2
705
+ return
706
+ else:
707
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.printer_status)
708
+
709
+ def _process_mqtt_update_ota_multicolorbox(
710
+ self,
711
+ action: str,
712
+ state: str,
713
+ payload: AnycubicConsumableData,
714
+ box_id: int,
715
+ ) -> None:
716
+ data = payload.get('data', {})
717
+ if (
718
+ self.multi_color_box_fw_version is None or
719
+ len(self.multi_color_box_fw_version) < (box_id + 1)
720
+ ):
721
+ return
722
+
723
+ if action == 'update' and state == 'start':
724
+ self.multi_color_box_fw_version[box_id].set_is_updating(True)
725
+ return
726
+ elif action == 'update' and state in ['update-success', 'updateSuccessProcessed']:
727
+ # Not needed
728
+ return
729
+ elif action == 'reportVersion' and state == 'done':
730
+ data.get('device_unionid')
731
+ data.get('machine_version')
732
+ data.get('peripheral_version')
733
+ data.get('model_id')
734
+ self.multi_color_box_fw_version[box_id].update_version(data['firmware_version'])
735
+ return
736
+ elif action == 'update' and state == 'downloading':
737
+ self.multi_color_box_fw_version[box_id].set_is_updating(True)
738
+ self.multi_color_box_fw_version[box_id].set_is_downloading(True)
739
+ self.multi_color_box_fw_version[box_id].set_download_progress(data['progress'])
740
+ return
741
+ elif action == 'update' and state == 'updating':
742
+ self.multi_color_box_fw_version[box_id].set_is_updating(True)
743
+ self.multi_color_box_fw_version[box_id].set_is_downloading(False)
744
+ self.multi_color_box_fw_version[box_id].set_update_progress(data['current_progress'])
745
+ return
746
+ else:
747
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.ota_ace)
748
+
749
+ def _process_mqtt_update_ota_printer(
750
+ self,
751
+ action: str,
752
+ state: str,
753
+ payload: AnycubicConsumableData,
754
+ ) -> None:
755
+ data = payload.get('data', {})
756
+
757
+ if action == 'reportVersion' and state == 'done':
758
+ data.get('device_unionid')
759
+ data.get('machine_version')
760
+ data.get('peripheral_version')
761
+ data.get('model_id')
762
+ if self.fw_version is not None:
763
+ self.fw_version.update_version(data['firmware_version'])
764
+ return
765
+ elif action == 'update' and state == 'start':
766
+ if self.fw_version is not None:
767
+ self.fw_version.set_is_updating(True)
768
+ return
769
+ elif action == 'update' and state == 'downloading':
770
+ if self.fw_version is not None:
771
+ self.fw_version.set_is_updating(True)
772
+ self.fw_version.set_is_downloading(True)
773
+ self.fw_version.set_download_progress(data['progress'])
774
+ return
775
+ elif action == 'update' and state == 'updating':
776
+ if self.fw_version is not None:
777
+ self.fw_version.set_is_updating(True)
778
+ self.fw_version.set_is_downloading(False)
779
+ self.fw_version.set_update_progress(data['current_progress'])
780
+ return
781
+ else:
782
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.ota_printer)
783
+
784
+ def _process_mqtt_update_temperature(
785
+ self,
786
+ action: str,
787
+ state: str,
788
+ payload: AnycubicConsumableData,
789
+ ) -> None:
790
+ if action == 'auto' and state == 'done':
791
+ data = payload['data']
792
+
793
+ if self.parameter:
794
+ self.parameter.update_current_temps(
795
+ data['curr_hotbed_temp'],
796
+ data['curr_nozzle_temp'],
797
+ )
798
+ if self._latest_project:
799
+ self._latest_project.update_target_temps(
800
+ data['target_hotbed_temp'],
801
+ data['target_nozzle_temp'],
802
+ )
803
+
804
+ return
805
+ else:
806
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.temperature)
807
+
808
+ def _process_mqtt_update_fan(
809
+ self,
810
+ action: str,
811
+ state: str,
812
+ payload: AnycubicConsumableData,
813
+ ) -> None:
814
+ if action == 'auto' and state == 'done':
815
+ data = payload['data']
816
+
817
+ self._fan_speed = int(data['fan_speed_pct'])
818
+
819
+ # The Kobra S1 also reports the auxiliary part fan and the ACE box
820
+ # fan here. Both were previously discarded as unhandled data.
821
+ if 'aux_fan_speed_pct' in data:
822
+ self._aux_fan_speed = int(data['aux_fan_speed_pct'])
823
+
824
+ if 'box_fan_level' in data:
825
+ self._box_fan_level = int(data['box_fan_level'])
826
+
827
+ return
828
+ else:
829
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.fan)
830
+
831
+ def _process_mqtt_update_print(
832
+ self,
833
+ action: str,
834
+ state: str,
835
+ payload: AnycubicConsumableData,
836
+ ) -> None:
837
+ project_id = payload.get('data', {}).get('taskid', -1)
838
+ if action == 'start' and state == 'printing':
839
+ data = payload['data']
840
+ self._is_printing = 2
841
+ self._update_latest_project_with_mqtt_print_status_data(
842
+ project_id,
843
+ AnycubicPrintStatus.Printing,
844
+ data,
845
+ )
846
+ return
847
+ elif action == 'start' and state == 'downloading':
848
+ data = payload['data']
849
+ self._is_printing = 2
850
+ self._update_latest_project_with_mqtt_download_status_data(
851
+ project_id,
852
+ data,
853
+ )
854
+ return
855
+ elif action == 'start' and state == 'checking':
856
+ self._is_printing = 2
857
+ self._update_latest_project_with_mqtt_checking_status_data(
858
+ project_id,
859
+ )
860
+ return
861
+ elif action == 'start' and state == 'preheating':
862
+ data = payload['data']
863
+ self._is_printing = 2
864
+ self._update_latest_project_with_mqtt_print_status_data(
865
+ project_id,
866
+ AnycubicPrintStatus.Preheating,
867
+ data,
868
+ )
869
+ return
870
+ elif action == 'start' and state == 'finished':
871
+ data = payload['data']
872
+ self._is_printing = 1
873
+ self._update_latest_project_with_mqtt_print_status_data(
874
+ project_id,
875
+ AnycubicPrintStatus.Complete,
876
+ data,
877
+ )
878
+ return
879
+ elif action == 'pause' and state in ['pausing', 'paused']:
880
+ data = payload['data']
881
+ self._is_printing = 2
882
+ self._update_latest_project_with_mqtt_print_status_data(
883
+ project_id,
884
+ AnycubicPrintStatus.Printing,
885
+ data,
886
+ paused=1,
887
+ )
888
+ return
889
+ elif action == 'resume' and state in ['resuming', 'resumed']:
890
+ data = payload['data']
891
+ self._is_printing = 2
892
+ self._update_latest_project_with_mqtt_print_status_data(
893
+ project_id,
894
+ AnycubicPrintStatus.Printing,
895
+ data,
896
+ paused=0 if state == 'resumed' else 1,
897
+ )
898
+ return
899
+ elif action in ['start', 'stop'] and state in ['stoped', 'stopping']:
900
+ data = payload['data']
901
+ self._is_printing = 1
902
+ self._update_latest_project_with_mqtt_print_status_data(
903
+ project_id,
904
+ AnycubicPrintStatus.Cancelled,
905
+ data,
906
+ )
907
+ return
908
+ elif action == 'getSliceParam' and state == 'done':
909
+ data = payload['data']['slice_param']
910
+ self._update_latest_project_slice_param(
911
+ project_id,
912
+ data,
913
+ )
914
+ return
915
+ elif action in ['start', 'update'] and state == 'updated':
916
+ data = payload['data']
917
+ if self.parameter:
918
+ self.parameter.update_current_temps(
919
+ data['curr_hotbed_temp'],
920
+ data['curr_nozzle_temp'],
921
+ )
922
+ self._fan_speed = int(data['settings']['fan_speed_pct'])
923
+ self._print_speed_pct = int(data['settings']['print_speed_pct'])
924
+ self._print_speed_mode = int(data['settings']['print_speed_mode'])
925
+ self._update_latest_project_target_temps(
926
+ project_id,
927
+ data['settings']['target_hotbed_temp'],
928
+ data['settings']['target_nozzle_temp'],
929
+ )
930
+ data['settings']
931
+ return
932
+ elif action in ['start', 'stop'] and state in ['failed']:
933
+ err_msg = payload.get('msg')
934
+ self._is_printing = 1
935
+ self._update_latest_project_with_mqtt_print_status_data(
936
+ project_id,
937
+ AnycubicPrintStatus.Cancelled,
938
+ reason=err_msg,
939
+ )
940
+ raise AnycubicAPIError(ErrorsGeneral.print_failed.format(err_msg))
941
+ else:
942
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.job_status)
943
+
944
+ def _process_mqtt_update_multicolorbox(
945
+ self,
946
+ action: str,
947
+ state: str,
948
+ payload: AnycubicConsumableData,
949
+ ) -> None:
950
+ if action == 'getInfo' and state == 'success':
951
+ # Consume the tool-head model so it stops being reported as
952
+ # unhandled data. Not currently surfaced anywhere.
953
+ payload['data'].get('head_tools_model')
954
+ data = payload['data']['multi_color_box']
955
+ self._set_multi_color_box(data)
956
+ return
957
+ elif action in ['setInfo', 'refresh'] and state == 'success':
958
+ data = payload['data']['multi_color_box']
959
+ for box in data:
960
+ box_id = int(box['id'])
961
+ if self.connected_ace_units < box_id + 1:
962
+ continue
963
+ assert self._multi_color_box
964
+ self._multi_color_box[box_id].update_slots_with_mqtt_data(box['slots'])
965
+ return
966
+
967
+ elif action == 'autoUpdateInfo' and state == 'done':
968
+ data = payload['data']
969
+ box_id = int(data['id'])
970
+ loaded_slot = int(data['loaded_slot'])
971
+ if self.connected_ace_units < box_id + 1:
972
+ return
973
+
974
+ assert self._multi_color_box
975
+ self._multi_color_box[box_id].set_slot_loaded(loaded_slot)
976
+ return
977
+ elif action in ['autoUpdateDryStatus', 'setDry'] and state == 'success':
978
+ data = payload['data']['multi_color_box']
979
+ for box in data:
980
+ box_id = int(box['id'])
981
+ if self.connected_ace_units < box_id + 1:
982
+ continue
983
+
984
+ assert self._multi_color_box
985
+ self._multi_color_box[box_id].set_current_temperature(box['temp'])
986
+ self._multi_color_box[box_id].set_drying_status(box['drying_status'])
987
+ return
988
+ elif action == 'feedFilament' and state == 'done':
989
+ data = payload['data']['multi_color_box']
990
+ for box in data:
991
+ box_id = int(box['id'])
992
+ if self.connected_ace_units < box_id + 1:
993
+ continue
994
+
995
+ loaded_slot = int(box['loaded_slot'])
996
+
997
+ assert self._multi_color_box
998
+ self._multi_color_box[box_id].set_slot_loaded(loaded_slot)
999
+ self._multi_color_box[box_id].set_feed_status(box['feed_status'])
1000
+ return
1001
+ elif action == 'setAutoFeed' and state == 'done':
1002
+ data = payload['data']['multi_color_box']
1003
+ for box in data:
1004
+ box_id = int(box['id'])
1005
+ if self.connected_ace_units < box_id + 1:
1006
+ continue
1007
+
1008
+ assert self._multi_color_box
1009
+ self._multi_color_box[box_id].set_auto_feed(box['auto_feed'])
1010
+ return
1011
+ else:
1012
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.ace)
1013
+
1014
+ def _process_mqtt_update_shelves(
1015
+ self,
1016
+ action: str,
1017
+ state: str,
1018
+ payload: AnycubicConsumableData,
1019
+ ) -> None:
1020
+ if action == 'reportInfo' and state == 'success':
1021
+ data = payload['data']
1022
+ if self.external_shelves:
1023
+ self.external_shelves.update_with_mqtt_data(data)
1024
+ return
1025
+ else:
1026
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.shelves)
1027
+
1028
+ def _process_mqtt_update_file(
1029
+ self,
1030
+ action: str,
1031
+ state: str,
1032
+ payload: AnycubicConsumableData,
1033
+ ) -> None:
1034
+ if action == 'listLocal' and state == 'done':
1035
+ data = payload['data']['records']
1036
+ self._set_local_file_list(data)
1037
+ return
1038
+ elif action == 'deleteLocal' and state == 'success':
1039
+ # Not Yet Needed
1040
+ return
1041
+ elif action == 'listUdisk' and state == 'done':
1042
+ data = payload['data']['records']
1043
+ self._set_udisk_file_list(data)
1044
+ return
1045
+ elif action == 'deleteUdisk' and state == 'success':
1046
+ # Not Yet Needed
1047
+ return
1048
+ elif action == 'cloudRecommendList' and state == 'done':
1049
+ # Not Yet Needed
1050
+ payload.force_empty()
1051
+ return
1052
+ else:
1053
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.file)
1054
+
1055
+ def _process_mqtt_update_peripherals(
1056
+ self,
1057
+ action: str,
1058
+ state: str,
1059
+ payload: AnycubicConsumableData,
1060
+ ) -> None:
1061
+ if action == 'query' and state == 'done':
1062
+ data = payload['data']
1063
+
1064
+ if 'camera' in data:
1065
+ self.set_has_peripheral_camera(data['camera'])
1066
+
1067
+ if 'multiColorBox' in data:
1068
+ self.set_has_peripheral_multi_color_box(data['multiColorBox'])
1069
+
1070
+ if 'udisk' in data:
1071
+ self.set_has_peripheral_udisk(data['udisk'])
1072
+
1073
+ return
1074
+ else:
1075
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.peripherals)
1076
+
1077
+ def _process_mqtt_update_light(
1078
+ self,
1079
+ action: str,
1080
+ state: str,
1081
+ payload: AnycubicConsumableData,
1082
+ ) -> None:
1083
+ # Two shapes, depending on the action:
1084
+ # query -> {'data': {'lights': [{'type': 2, 'status': 1, 'brightness': 100}]}}
1085
+ # control -> {'data': {'type': 2, 'status': 1, 'brightness': 100}}
1086
+ if state != 'done':
1087
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.unknown.format('light'))
1088
+
1089
+ data = payload['data']
1090
+
1091
+ if not data:
1092
+ return
1093
+
1094
+ if 'lights' in data:
1095
+ reported = data['lights']
1096
+ elif 'type' in data:
1097
+ reported = [{
1098
+ 'type': data['type'],
1099
+ 'status': data.get('status'),
1100
+ 'brightness': data.get('brightness'),
1101
+ }]
1102
+ else:
1103
+ return
1104
+
1105
+ for light in reported:
1106
+ light_type = light.get('type')
1107
+
1108
+ if light_type is None:
1109
+ continue
1110
+
1111
+ self._lights[int(light_type)] = {
1112
+ 'status': int(light.get('status') or 0),
1113
+ 'brightness': int(light.get('brightness') or 0),
1114
+ }
1115
+
1116
+ def process_mqtt_update(
1117
+ self,
1118
+ topic: str,
1119
+ payload: AnycubicConsumableData,
1120
+ ) -> None:
1121
+ msg_type = payload['type']
1122
+ action = payload['action']
1123
+ state = payload.get('state')
1124
+ multi_color_topic = bool('multiColorBox' in topic)
1125
+
1126
+ if msg_type == 'lastWill':
1127
+ self._process_mqtt_update_lastwill(action, state, payload)
1128
+
1129
+ elif msg_type == 'user':
1130
+ self._process_mqtt_update_user(action, state, payload)
1131
+
1132
+ elif msg_type == 'status':
1133
+ self._process_mqtt_update_status(action, state, payload)
1134
+
1135
+ elif msg_type == 'ota' and multi_color_topic:
1136
+ box_id_str = get_part_from_mqtt_topic(topic, 9)
1137
+ box_id = int(box_id_str) if box_id_str and box_id_str.isdigit() else 0
1138
+ self._process_mqtt_update_ota_multicolorbox(action, state, payload, box_id)
1139
+
1140
+ elif msg_type == 'ota':
1141
+ self._process_mqtt_update_ota_printer(action, state, payload)
1142
+
1143
+ elif msg_type == 'tempature':
1144
+ self._process_mqtt_update_temperature(action, state, payload)
1145
+
1146
+ elif msg_type == 'fan':
1147
+ self._process_mqtt_update_fan(action, state, payload)
1148
+
1149
+ elif msg_type == 'print':
1150
+ self._process_mqtt_update_print(action, state, payload)
1151
+
1152
+ elif msg_type == 'multiColorBox':
1153
+ self._process_mqtt_update_multicolorbox(action, state, payload)
1154
+
1155
+ elif msg_type == 'extfilbox':
1156
+ self._process_mqtt_update_shelves(action, state, payload)
1157
+
1158
+ elif msg_type == 'file':
1159
+ self._process_mqtt_update_file(action, state, payload)
1160
+
1161
+ elif msg_type == 'peripherie':
1162
+ self._process_mqtt_update_peripherals(action, state, payload)
1163
+
1164
+ elif msg_type == 'light':
1165
+ self._process_mqtt_update_light(action, state, payload)
1166
+
1167
+ else:
1168
+ raise AnycubicMQTTUnknownUpdate(ErrorsMQTTUpdate.unknown.format(msg_type))
1169
+
1170
+ remaining_data: AnycubicConsumableData | None = payload.get('data')
1171
+
1172
+ if remaining_data:
1173
+ remaining_data.get('taskid')
1174
+ remaining_data.get('localtask')
1175
+
1176
+ payload.get('data')
1177
+ payload.get('msg')
1178
+ payload.get('timestamp')
1179
+ payload.get('msgid')
1180
+ payload.get('code')
1181
+
1182
+ if not payload.is_empty:
1183
+ raise AnycubicMQTTUnhandledData(
1184
+ "process_mqtt_update",
1185
+ unhandled_mqtt_data=payload.remaining_data,
1186
+ unhandled_mqtt_type=msg_type,
1187
+ unhandled_mqtt_action=action,
1188
+ unhandled_mqtt_state=state,
1189
+ )
1190
+
1191
+ @property
1192
+ def initialisation_error(self) -> bool:
1193
+ return self._initialisation_error
1194
+
1195
+ @property
1196
+ def machine_type(self) -> int:
1197
+ return self._machine_type
1198
+
1199
+ @property
1200
+ def model(self) -> str:
1201
+ return self._machine_name
1202
+
1203
+ @property
1204
+ def machine_name(self) -> str:
1205
+ return self._machine_name
1206
+
1207
+ @property
1208
+ def machine_img(self) -> str | None:
1209
+ return self._machine_img
1210
+
1211
+ @property
1212
+ def net_function_ids(self) -> list[int] | None:
1213
+ return self._net_function_ids
1214
+
1215
+ @property
1216
+ def net_default_function(self) -> int | None:
1217
+ return self._net_default_function
1218
+
1219
+ @property
1220
+ def id(self) -> int:
1221
+ if self._id is None:
1222
+ raise AnycubicAPIError(ErrorsGeneral.noid_printer)
1223
+ return self._id
1224
+
1225
+ @property
1226
+ def user_id(self) -> int | None:
1227
+ return self._user_id
1228
+
1229
+ @property
1230
+ def name(self) -> str | None:
1231
+ return self._name
1232
+
1233
+ @property
1234
+ def nonce(self) -> str | int | None:
1235
+ return self._nonce
1236
+
1237
+ @property
1238
+ def key(self) -> str | None:
1239
+ return self._key
1240
+
1241
+ @property
1242
+ def user_img(self) -> str | None:
1243
+ return self._user_img
1244
+
1245
+ @property
1246
+ def description(self) -> str | None:
1247
+ return self._description
1248
+
1249
+ @property
1250
+ def printer_type(self) -> str | None:
1251
+ return self._printer_type
1252
+
1253
+ @property
1254
+ def device_status(self) -> int | None:
1255
+ return self._device_status
1256
+
1257
+ @property
1258
+ def printer_online(self) -> bool:
1259
+ return self._device_status == 1
1260
+
1261
+ @property
1262
+ def ready_status(self) -> int | None:
1263
+ return self._ready_status
1264
+
1265
+ @property
1266
+ def is_printing(self) -> int:
1267
+ return self._is_printing
1268
+
1269
+ @property
1270
+ def is_available(self) -> bool:
1271
+ return self._is_printing == 1
1272
+
1273
+ @property
1274
+ def is_busy(self) -> bool:
1275
+ return self._is_printing == 2
1276
+
1277
+ @property
1278
+ def reason(self) -> str | None:
1279
+ return self._reason
1280
+
1281
+ @property
1282
+ def current_status(self) -> str:
1283
+ if self.is_busy:
1284
+ return "busy"
1285
+ elif self.is_available:
1286
+ return "available"
1287
+ else:
1288
+ return "unknown"
1289
+
1290
+ @property
1291
+ def video_taskid(self) -> int | None:
1292
+ return self._video_taskid
1293
+
1294
+ @property
1295
+ def msg(self) -> str | None:
1296
+ return self._msg
1297
+
1298
+ @property
1299
+ def material_used(self) -> str | None:
1300
+ return self._material_used
1301
+
1302
+ @property
1303
+ def material_used_kg(self) -> float | None:
1304
+ """Lifetime filament use as a number. The API reports e.g. '18.01kg'."""
1305
+ if not self._material_used:
1306
+ return None
1307
+
1308
+ match = re.match(r"\s*([0-9]*\.?[0-9]+)\s*kg", str(self._material_used), re.I)
1309
+
1310
+ if not match:
1311
+ return None
1312
+
1313
+ return float(match.group(1))
1314
+
1315
+ @property
1316
+ def total_print_time(self) -> str | None:
1317
+ return self._total_print_time
1318
+
1319
+ @property
1320
+ def total_print_time_delta(self) -> timedelta:
1321
+ return self._total_print_time_delta
1322
+
1323
+ @property
1324
+ def total_print_time_hrs(self) -> int:
1325
+ return self._total_print_time_hrs
1326
+
1327
+ @property
1328
+ def total_print_time_dhm_str(self) -> str:
1329
+ return self._total_print_time_dhm_str
1330
+
1331
+ @property
1332
+ def print_count(self) -> int | None:
1333
+ return self._print_count
1334
+
1335
+ @property
1336
+ def status(self) -> int | None:
1337
+ return self._status
1338
+
1339
+ @property
1340
+ def machine_mac(self) -> str | None:
1341
+ return self._machine_mac
1342
+
1343
+ @property
1344
+ def delete(self) -> int | None:
1345
+ return self._delete
1346
+
1347
+ @property
1348
+ def create_time(self) -> int | None:
1349
+ return self._create_time
1350
+
1351
+ @property
1352
+ def delete_time(self) -> int | None:
1353
+ return self._delete_time
1354
+
1355
+ @property
1356
+ def last_update_time(self) -> int | None:
1357
+ return self._last_update_time
1358
+
1359
+ @property
1360
+ def machine_data(self) -> AnycubicMachineData | None:
1361
+ return self._machine_data
1362
+
1363
+ @property
1364
+ def type_function_ids(self) -> list[int]:
1365
+ return self._type_function_ids
1366
+
1367
+ @property
1368
+ def supports_function_axle_movement(self) -> bool:
1369
+ return AnycubicFunctionID.AXLE_MOVEMENT in self._type_function_ids
1370
+
1371
+ @property
1372
+ def supports_function_file_manager(self) -> bool:
1373
+ return AnycubicFunctionID.FILE_MANAGER in self._type_function_ids
1374
+
1375
+ @property
1376
+ def supports_function_exposure_test(self) -> bool:
1377
+ return AnycubicFunctionID.EXPOSURE_TEST in self._type_function_ids
1378
+
1379
+ @property
1380
+ def supports_function_lcd_peer_video(self) -> bool:
1381
+ return AnycubicFunctionID.LCD_PEER_VIDEO in self._type_function_ids
1382
+
1383
+ @property
1384
+ def supports_function_fdm_axis_move(self) -> bool:
1385
+ return AnycubicFunctionID.FDM_AXIS_MOVE in self._type_function_ids
1386
+
1387
+ @property
1388
+ def supports_function_fdm_peer_video(self) -> bool:
1389
+ return AnycubicFunctionID.FDM_PEER_VIDEO in self._type_function_ids
1390
+
1391
+ @property
1392
+ def supports_function_device_startup_self_test(self) -> bool:
1393
+ return AnycubicFunctionID.DEVICE_STARTUP_SELF_TEST in self._type_function_ids
1394
+
1395
+ @property
1396
+ def supports_function_print_startup_self_test(self) -> bool:
1397
+ return AnycubicFunctionID.PRINT_STARTUP_SELF_TEST in self._type_function_ids
1398
+
1399
+ @property
1400
+ def supports_function_automatic_operation(self) -> bool:
1401
+ return AnycubicFunctionID.AUTOMATIC_OPERATION in self._type_function_ids
1402
+
1403
+ @property
1404
+ def supports_function_residue_clean(self) -> bool:
1405
+ return AnycubicFunctionID.RESIDUE_CLEAN in self._type_function_ids
1406
+
1407
+ @property
1408
+ def supports_function_novice_guide(self) -> bool:
1409
+ return AnycubicFunctionID.NOVICE_GUIDE in self._type_function_ids
1410
+
1411
+ @property
1412
+ def supports_function_release_film(self) -> bool:
1413
+ return AnycubicFunctionID.RELEASE_FILM in self._type_function_ids
1414
+
1415
+ @property
1416
+ def supports_function_task_mode(self) -> bool:
1417
+ return AnycubicFunctionID.TASK_MODE in self._type_function_ids
1418
+
1419
+ @property
1420
+ def supports_function_lcd_intelligent_materials_box(self) -> bool:
1421
+ return AnycubicFunctionID.LCD_INTELLIGENT_MATERIALS_BOX in self._type_function_ids
1422
+
1423
+ @property
1424
+ def supports_function_lcd_auto_out_in_materials(self) -> bool:
1425
+ return AnycubicFunctionID.LCD_AUTO_OUT_IN_MATERIALS in self._type_function_ids
1426
+
1427
+ @property
1428
+ def supports_function_m7pro_automatic_operation(self) -> bool:
1429
+ return AnycubicFunctionID.M7PRO_AUTOMATIC_OPERATION in self._type_function_ids
1430
+
1431
+ @property
1432
+ def supports_function_multi_color_box(self) -> bool:
1433
+ return AnycubicFunctionID.MULTI_COLOR_BOX in self._type_function_ids
1434
+
1435
+ @property
1436
+ def supports_function_ai_detection(self) -> bool:
1437
+ return AnycubicFunctionID.AI_DETECTION in self._type_function_ids
1438
+
1439
+ @property
1440
+ def supports_function_auto_leveler(self) -> bool:
1441
+ return AnycubicFunctionID.AUTO_LEVELER in self._type_function_ids
1442
+
1443
+ @property
1444
+ def supports_function_vibration_compensation(self) -> bool:
1445
+ return AnycubicFunctionID.VIBRATION_COMPENSATION in self._type_function_ids
1446
+
1447
+ @property
1448
+ def supports_function_time_lapse(self) -> bool:
1449
+ return AnycubicFunctionID.TIME_LAPSE in self._type_function_ids
1450
+
1451
+ @property
1452
+ def supports_function_video_light(self) -> bool:
1453
+ return AnycubicFunctionID.VIDEO_LIGHT in self._type_function_ids
1454
+
1455
+ @property
1456
+ def supports_function_box_light(self) -> bool:
1457
+ return AnycubicFunctionID.BOX_LIGHT in self._type_function_ids
1458
+
1459
+ @property
1460
+ def supported_function_strings(self) -> list[str]:
1461
+ func_ids = list()
1462
+ for func_int in self._type_function_ids:
1463
+ try:
1464
+ func_ids.append(AnycubicFunctionID(int(func_int)))
1465
+ except ValueError:
1466
+ pass
1467
+
1468
+ return list([
1469
+ func_id.name for func_id in func_ids
1470
+ ])
1471
+
1472
+ @property
1473
+ def aux_fan_speed_pct(self) -> int | None:
1474
+ return self._aux_fan_speed
1475
+
1476
+ @property
1477
+ def box_fan_level(self) -> int | None:
1478
+ return self._box_fan_level
1479
+
1480
+ @property
1481
+ def light_type(self) -> int | None:
1482
+ """The light `type` this printer reports. Kobra S1 uses 2, not 1."""
1483
+ if not self._lights:
1484
+ return None
1485
+
1486
+ return sorted(self._lights.keys())[0]
1487
+
1488
+ @property
1489
+ def has_controllable_light(self) -> bool:
1490
+ return bool(self._lights)
1491
+
1492
+ @property
1493
+ def light_is_on(self) -> bool:
1494
+ light_type = self.light_type
1495
+
1496
+ if light_type is None:
1497
+ return False
1498
+
1499
+ return bool(self._lights[light_type]['status'])
1500
+
1501
+ @property
1502
+ def light_brightness_pct(self) -> int | None:
1503
+ light_type = self.light_type
1504
+
1505
+ if light_type is None:
1506
+ return None
1507
+
1508
+ return self._lights[light_type]['brightness']
1509
+
1510
+ @property
1511
+ def has_peripheral_camera(self) -> bool:
1512
+ return self._has_peripheral_camera
1513
+
1514
+ @property
1515
+ def has_peripheral_multi_color_box(self) -> bool:
1516
+ return self._has_peripheral_multi_color_box
1517
+
1518
+ @property
1519
+ def has_peripheral_udisk(self) -> bool:
1520
+ return self._has_peripheral_udisk
1521
+
1522
+ @property
1523
+ def connected_peripherals(self) -> dict[str, bool]:
1524
+ return {
1525
+ "camera": self.has_peripheral_camera,
1526
+ "ace": self.has_peripheral_multi_color_box,
1527
+ "usb_disk": self.has_peripheral_udisk,
1528
+ }
1529
+
1530
+ @property
1531
+ def material_type(self) -> AnycubicPrinterMaterialType | str | None:
1532
+ return self._material_type
1533
+
1534
+ @property
1535
+ def parameter(self) -> AnycubicMachineParameter | None:
1536
+ if not self._parameter:
1537
+ return None
1538
+
1539
+ return self._parameter
1540
+
1541
+ @property
1542
+ def fw_version(self) -> AnycubicMachineFirmwareInfo | None:
1543
+ return self._fw_version
1544
+
1545
+ @property
1546
+ def available(self) -> int | None:
1547
+ return self._available
1548
+
1549
+ @property
1550
+ def color(self) -> AnycubicMachineColorInfo | None:
1551
+ return self._color
1552
+
1553
+ @property
1554
+ def advance(self) -> list[Any] | None:
1555
+ return self._advance
1556
+
1557
+ @property
1558
+ def tools(self) -> list[AnycubicMachineToolInfo] | None:
1559
+ return self._tools
1560
+
1561
+ @property
1562
+ def multi_color_box_fw_version(self) -> list[AnycubicMachineFirmwareInfo] | None:
1563
+ return self._multi_color_box_fw_version
1564
+
1565
+ @property
1566
+ def external_shelves(self) -> AnycubicMachineExternalShelves | None:
1567
+ return self._external_shelves
1568
+
1569
+ @property
1570
+ def multi_color_box(self) -> list[AnycubicMultiColorBox] | None:
1571
+ return self._multi_color_box
1572
+
1573
+ @property
1574
+ def connected_ace_units(self) -> int:
1575
+ if self._multi_color_box is None:
1576
+ return 0
1577
+
1578
+ return len(self._multi_color_box)
1579
+
1580
+ @property
1581
+ def primary_multi_color_box(self) -> AnycubicMultiColorBox | None:
1582
+ if self.connected_ace_units > 0:
1583
+ assert self._multi_color_box
1584
+ return self._multi_color_box[0]
1585
+
1586
+ return None
1587
+
1588
+ @property
1589
+ def secondary_multi_color_box(self) -> AnycubicMultiColorBox | None:
1590
+ if self.connected_ace_units > 1:
1591
+ assert self._multi_color_box
1592
+ return self._multi_color_box[1]
1593
+
1594
+ return None
1595
+
1596
+ @property
1597
+ def primary_drying_status(self) -> AnycubicDryingStatus | None:
1598
+ if self.primary_multi_color_box is None:
1599
+ return None
1600
+
1601
+ return self.primary_multi_color_box.drying_status
1602
+
1603
+ @property
1604
+ def secondary_drying_status(self) -> AnycubicDryingStatus | None:
1605
+ if self.secondary_multi_color_box is None:
1606
+ return None
1607
+
1608
+ return self.secondary_multi_color_box.drying_status
1609
+
1610
+ @property
1611
+ def latest_project(self) -> AnycubicProject | None:
1612
+ return self._latest_project
1613
+
1614
+ @property
1615
+ def local_file_list_object(self) -> list[dict[str, str | float]] | None:
1616
+ if not self._local_file_list or len(self._local_file_list) < 1:
1617
+ return None
1618
+
1619
+ file_list = list([
1620
+ file.data_object for file in self._local_file_list
1621
+ ])
1622
+ return file_list
1623
+
1624
+ @property
1625
+ def udisk_file_list_object(self) -> list[dict[str, str | float]] | None:
1626
+ if not self._udisk_file_list or len(self._udisk_file_list) < 1:
1627
+ return None
1628
+
1629
+ file_list = list([
1630
+ file.data_object for file in self._udisk_file_list
1631
+ ])
1632
+ return file_list
1633
+
1634
+ @property
1635
+ def primary_multi_color_box_fw_firmware_version(self) -> str | None:
1636
+ if (
1637
+ self.multi_color_box_fw_version and
1638
+ len(self.multi_color_box_fw_version) > 0
1639
+ ):
1640
+ return self.multi_color_box_fw_version[0].firmware_version
1641
+
1642
+ return None
1643
+
1644
+ @property
1645
+ def primary_multi_color_box_fw_available_version(self) -> str | None:
1646
+ if (
1647
+ self.multi_color_box_fw_version and
1648
+ len(self.multi_color_box_fw_version) > 0
1649
+ ):
1650
+ return self.multi_color_box_fw_version[0].available_version
1651
+
1652
+ return None
1653
+
1654
+ @property
1655
+ def primary_multi_color_box_fw_total_progress(self) -> int | float | bool | None:
1656
+ if (
1657
+ self.multi_color_box_fw_version and
1658
+ len(self.multi_color_box_fw_version) > 0
1659
+ ):
1660
+ return self.multi_color_box_fw_version[0].total_progress
1661
+
1662
+ return None
1663
+
1664
+ @property
1665
+ def primary_multi_color_box_auto_feed(self) -> int | None:
1666
+ if self.primary_multi_color_box:
1667
+ return self.primary_multi_color_box.auto_feed
1668
+
1669
+ return None
1670
+
1671
+ @property
1672
+ def primary_multi_color_box_spool_info_object(self) -> list[dict[str, Any]] | None:
1673
+ if self.primary_multi_color_box:
1674
+ return self.primary_multi_color_box.spool_info_object
1675
+
1676
+ return None
1677
+
1678
+ @property
1679
+ def primary_multi_color_box_current_temperature(self) -> int:
1680
+ if self.primary_multi_color_box:
1681
+ return self.primary_multi_color_box.current_temperature
1682
+
1683
+ return 0
1684
+
1685
+ @property
1686
+ def primary_multi_color_box_info_object(self) -> dict[str, Any] | None:
1687
+ if self.primary_multi_color_box:
1688
+ return self.primary_multi_color_box.box_info_object
1689
+
1690
+ return None
1691
+
1692
+ @property
1693
+ def primary_multi_color_box_loaded_slot(self) -> int | None:
1694
+ if self.primary_multi_color_box:
1695
+ slot = self.primary_multi_color_box.loaded_slot
1696
+ # -1 means nothing is loaded; surface that as unknown rather than
1697
+ # a slot number that doesn't exist.
1698
+ return slot if slot is not None and slot >= 0 else None
1699
+
1700
+ return None
1701
+
1702
+ @property
1703
+ def primary_drying_status_is_drying(self) -> bool | None:
1704
+ if self.primary_drying_status:
1705
+ return self.primary_drying_status.is_drying
1706
+
1707
+ return None
1708
+
1709
+ @property
1710
+ def primary_drying_status_raw_status_code(self) -> int | None:
1711
+ if self.primary_drying_status:
1712
+ return self.primary_drying_status.raw_status_code
1713
+
1714
+ return None
1715
+
1716
+ @property
1717
+ def primary_drying_status_target_temperature(self) -> int:
1718
+ if self.primary_drying_status:
1719
+ return self.primary_drying_status.target_temperature
1720
+
1721
+ return 0
1722
+
1723
+ @property
1724
+ def primary_drying_status_total_duration(self) -> int:
1725
+ if self.primary_drying_status:
1726
+ return self.primary_drying_status.total_duration
1727
+
1728
+ return 0
1729
+
1730
+ @property
1731
+ def primary_drying_status_remaining_time(self) -> int:
1732
+ if self.primary_drying_status:
1733
+ return self.primary_drying_status.remaining_time
1734
+
1735
+ return 0
1736
+
1737
+ @property
1738
+ def secondary_multi_color_box_fw_firmware_version(self) -> str | None:
1739
+ if (
1740
+ self.multi_color_box_fw_version and
1741
+ len(self.multi_color_box_fw_version) > 1
1742
+ ):
1743
+ return self.multi_color_box_fw_version[1].firmware_version
1744
+
1745
+ return None
1746
+
1747
+ @property
1748
+ def secondary_multi_color_box_fw_available_version(self) -> str | None:
1749
+ if (
1750
+ self.multi_color_box_fw_version and
1751
+ len(self.multi_color_box_fw_version) > 1
1752
+ ):
1753
+ return self.multi_color_box_fw_version[1].available_version
1754
+
1755
+ return None
1756
+
1757
+ @property
1758
+ def secondary_multi_color_box_fw_total_progress(self) -> int | float | bool | None:
1759
+ if (
1760
+ self.multi_color_box_fw_version and
1761
+ len(self.multi_color_box_fw_version) > 1
1762
+ ):
1763
+ return self.multi_color_box_fw_version[1].total_progress
1764
+
1765
+ return None
1766
+
1767
+ @property
1768
+ def secondary_multi_color_box_auto_feed(self) -> int | None:
1769
+ if self.secondary_multi_color_box:
1770
+ return self.secondary_multi_color_box.auto_feed
1771
+
1772
+ return None
1773
+
1774
+ @property
1775
+ def secondary_multi_color_box_spool_info_object(self) -> list[dict[str, Any]] | None:
1776
+ if self.secondary_multi_color_box:
1777
+ return self.secondary_multi_color_box.spool_info_object
1778
+
1779
+ return None
1780
+
1781
+ @property
1782
+ def secondary_multi_color_box_current_temperature(self) -> int:
1783
+ if self.secondary_multi_color_box:
1784
+ return self.secondary_multi_color_box.current_temperature
1785
+
1786
+ return 0
1787
+
1788
+ @property
1789
+ def secondary_drying_status_is_drying(self) -> bool | None:
1790
+ if self.secondary_drying_status:
1791
+ return self.secondary_drying_status.is_drying
1792
+
1793
+ return None
1794
+
1795
+ @property
1796
+ def secondary_drying_status_raw_status_code(self) -> int | None:
1797
+ if self.secondary_drying_status:
1798
+ return self.secondary_drying_status.raw_status_code
1799
+
1800
+ return None
1801
+
1802
+ @property
1803
+ def secondary_drying_status_target_temperature(self) -> int:
1804
+ if self.secondary_drying_status:
1805
+ return self.secondary_drying_status.target_temperature
1806
+
1807
+ return 0
1808
+
1809
+ @property
1810
+ def secondary_drying_status_total_duration(self) -> int:
1811
+ if self.secondary_drying_status:
1812
+ return self.secondary_drying_status.total_duration
1813
+
1814
+ return 0
1815
+
1816
+ @property
1817
+ def secondary_drying_status_remaining_time(self) -> int:
1818
+ if self.secondary_drying_status:
1819
+ return self.secondary_drying_status.remaining_time
1820
+
1821
+ return 0
1822
+
1823
+ @property
1824
+ def latest_project_name(self) -> str | None:
1825
+ if self.latest_project:
1826
+ return self.latest_project.name
1827
+
1828
+ return None
1829
+
1830
+ @property
1831
+ def latest_project_image_url(self) -> str | None:
1832
+ if self.latest_project:
1833
+ return self.latest_project.image_url
1834
+
1835
+ return None
1836
+
1837
+ @property
1838
+ def latest_project_progress_percentage(self) -> int | None:
1839
+ if self.latest_project:
1840
+ return self.latest_project.progress_percentage
1841
+
1842
+ return None
1843
+
1844
+ @property
1845
+ def latest_project_created_timestamp(self) -> int | None:
1846
+ if self.latest_project:
1847
+ return self.latest_project.created_timestamp
1848
+
1849
+ return None
1850
+
1851
+ @property
1852
+ def latest_project_finished_timestamp(self) -> int | None:
1853
+ if self.latest_project:
1854
+ return self.latest_project.finished_timestamp
1855
+
1856
+ return None
1857
+
1858
+ @property
1859
+ def latest_project_print_time_elapsed_minutes(self) -> int | None:
1860
+ if self.latest_project:
1861
+ return self.latest_project.print_time_elapsed_minutes
1862
+
1863
+ return None
1864
+
1865
+ @property
1866
+ def latest_project_print_time_remaining_minutes(self) -> int | None:
1867
+ if self.latest_project:
1868
+ return self.latest_project.print_time_remaining_minutes
1869
+
1870
+ return None
1871
+
1872
+ @property
1873
+ def latest_project_print_status_message(self) -> str | None:
1874
+ if self.latest_project:
1875
+ return self.latest_project.print_status_message
1876
+
1877
+ return None
1878
+
1879
+ @property
1880
+ def latest_project_print_total_time(self) -> str | None:
1881
+ if self.latest_project:
1882
+ return self.latest_project.print_total_time
1883
+
1884
+ return None
1885
+
1886
+ @property
1887
+ def latest_project_print_total_time_delta(self) -> timedelta | None:
1888
+ if self.latest_project:
1889
+ return self.latest_project.print_total_time_delta
1890
+
1891
+ return None
1892
+
1893
+ @property
1894
+ def latest_project_print_total_time_minutes(self) -> int | None:
1895
+ if self.latest_project:
1896
+ return self.latest_project.print_total_time_minutes
1897
+
1898
+ return None
1899
+
1900
+ @property
1901
+ def latest_project_print_total_time_dhm_str(self) -> str | None:
1902
+ if self.latest_project:
1903
+ return self.latest_project.print_total_time_dhm_str
1904
+
1905
+ return None
1906
+
1907
+ @property
1908
+ def latest_project_print_in_progress(self) -> bool | None:
1909
+ if self.latest_project:
1910
+ return self.latest_project.print_in_progress
1911
+
1912
+ return None
1913
+
1914
+ @property
1915
+ def latest_project_print_complete(self) -> bool | None:
1916
+ if self.latest_project:
1917
+ return self.latest_project.print_complete
1918
+
1919
+ return None
1920
+
1921
+ @property
1922
+ def latest_project_print_failed(self) -> bool | None:
1923
+ if self.latest_project:
1924
+ return self.latest_project.print_failed
1925
+
1926
+ return None
1927
+
1928
+ @property
1929
+ def latest_project_print_is_paused(self) -> bool | None:
1930
+ if self.latest_project:
1931
+ return self.latest_project.print_is_paused
1932
+
1933
+ return None
1934
+
1935
+ @property
1936
+ def latest_project_print_status(self) -> str | None:
1937
+ if self.latest_project:
1938
+ return self.latest_project.print_status
1939
+
1940
+ return None
1941
+
1942
+ @property
1943
+ def latest_project_print_approximate_completion_time(self) -> int | None:
1944
+ if self.latest_project:
1945
+ return self.latest_project.print_approximate_completion_time
1946
+
1947
+ return None
1948
+
1949
+ @property
1950
+ def latest_project_print_current_layer(self) -> int | None:
1951
+ if self.latest_project:
1952
+ return self.latest_project.print_current_layer
1953
+
1954
+ return None
1955
+
1956
+ @property
1957
+ def latest_project_job_details(self) -> dict[str, Any] | None:
1958
+ if self.latest_project:
1959
+ return self.latest_project.job_details_object
1960
+
1961
+ return None
1962
+
1963
+ @property
1964
+ def latest_project_supplies_usage(self) -> int | None:
1965
+ """Filament consumed by the current job, as reported by the printer."""
1966
+ if self.latest_project:
1967
+ return self.latest_project.print_supplies_usage
1968
+
1969
+ return None
1970
+
1971
+ @property
1972
+ def latest_project_print_supplies_usage(self) -> int | None:
1973
+ if self.latest_project:
1974
+ return self.latest_project.print_supplies_usage
1975
+
1976
+ return None
1977
+
1978
+ @property
1979
+ def latest_project_print_total_layers(self) -> int | None:
1980
+ if self.latest_project:
1981
+ return self.latest_project.print_total_layers
1982
+
1983
+ return None
1984
+
1985
+ @property
1986
+ def latest_project_target_nozzle_temp(self) -> int | None:
1987
+ if self.latest_project:
1988
+ return self.latest_project.target_nozzle_temp
1989
+
1990
+ return None
1991
+
1992
+ @property
1993
+ def latest_project_temp_min_nozzle(self) -> int | None:
1994
+ if self.latest_project:
1995
+ return self.latest_project.temp_min_nozzle
1996
+
1997
+ return None
1998
+
1999
+ @property
2000
+ def latest_project_temp_max_nozzle(self) -> int | None:
2001
+ if self.latest_project:
2002
+ return self.latest_project.temp_max_nozzle
2003
+
2004
+ return None
2005
+
2006
+ @property
2007
+ def latest_project_target_hotbed_temp(self) -> int | None:
2008
+ if self.latest_project:
2009
+ return self.latest_project.target_hotbed_temp
2010
+
2011
+ return None
2012
+
2013
+ @property
2014
+ def latest_project_temp_min_hotbed(self) -> int | None:
2015
+ if self.latest_project:
2016
+ return self.latest_project.temp_min_hotbed
2017
+
2018
+ return None
2019
+
2020
+ @property
2021
+ def latest_project_temp_max_hotbed(self) -> int | None:
2022
+ if self.latest_project:
2023
+ return self.latest_project.temp_max_hotbed
2024
+
2025
+ return None
2026
+
2027
+ @property
2028
+ def latest_project_print_speed_mode(self) -> int | None:
2029
+ if self.latest_project:
2030
+ return self.latest_project.print_speed_mode
2031
+
2032
+ return None
2033
+
2034
+ @property
2035
+ def latest_project_print_speed_mode_string(self) -> str | None:
2036
+ if self.latest_project:
2037
+ return self.latest_project.print_speed_mode_string
2038
+
2039
+ return None
2040
+
2041
+ @property
2042
+ def latest_project_print_speed_pct(self) -> int | None:
2043
+ if self.latest_project:
2044
+ return self.latest_project.print_speed_pct
2045
+
2046
+ return None
2047
+
2048
+ @property
2049
+ def latest_project_z_thick(self) -> float | None:
2050
+ if self.latest_project:
2051
+ return self.latest_project.z_thick
2052
+
2053
+ return None
2054
+
2055
+ @property
2056
+ def latest_project_fan_speed_pct(self) -> int | None:
2057
+ if self.latest_project:
2058
+ return self.latest_project.fan_speed_pct
2059
+
2060
+ return None
2061
+
2062
+ @property
2063
+ def latest_project_raw_print_status(self) -> int | None:
2064
+ if self.latest_project:
2065
+ return self.latest_project.raw_print_status
2066
+
2067
+ return None
2068
+
2069
+ @property
2070
+ def latest_project_available_print_speed_modes_data_object(self) -> list[dict[str, str | int]] | None:
2071
+ if self.latest_project:
2072
+ return self.latest_project.available_print_speed_modes_data_object
2073
+
2074
+ return None
2075
+
2076
+ @property
2077
+ def latest_project_print_model_height(self) -> float | None:
2078
+ if self.latest_project:
2079
+ return self.latest_project.print_model_height
2080
+
2081
+ return None
2082
+
2083
+ @property
2084
+ def latest_project_print_anti_alias_count(self) -> int | None:
2085
+ if self.latest_project:
2086
+ return self.latest_project.print_anti_alias_count
2087
+
2088
+ return None
2089
+
2090
+ @property
2091
+ def latest_project_print_on_time(self) -> float | None:
2092
+ if self.latest_project:
2093
+ return self.latest_project.print_on_time
2094
+
2095
+ return None
2096
+
2097
+ @property
2098
+ def latest_project_print_off_time(self) -> float | None:
2099
+ if self.latest_project:
2100
+ return self.latest_project.print_off_time
2101
+
2102
+ return None
2103
+
2104
+ @property
2105
+ def latest_project_print_bottom_time(self) -> float | None:
2106
+ if self.latest_project:
2107
+ return self.latest_project.print_bottom_time
2108
+
2109
+ return None
2110
+
2111
+ @property
2112
+ def latest_project_print_bottom_layers(self) -> int | None:
2113
+ if self.latest_project:
2114
+ return self.latest_project.print_bottom_layers
2115
+
2116
+ return None
2117
+
2118
+ @property
2119
+ def latest_project_print_z_up_height(self) -> float | None:
2120
+ if self.latest_project:
2121
+ return self.latest_project.print_z_up_height
2122
+
2123
+ return None
2124
+
2125
+ @property
2126
+ def latest_project_print_z_up_speed(self) -> int | None:
2127
+ if self.latest_project:
2128
+ return self.latest_project.print_z_up_speed
2129
+
2130
+ return None
2131
+
2132
+ @property
2133
+ def latest_project_print_z_down_speed(self) -> int | None:
2134
+ if self.latest_project:
2135
+ return self.latest_project.print_z_down_speed
2136
+
2137
+ return None
2138
+
2139
+ @property
2140
+ def latest_project_download_progress_percentage(self) -> int:
2141
+ if self._job_download_progress:
2142
+ return self._job_download_progress
2143
+ elif self.latest_project:
2144
+ return self.latest_project.download_progress_percentage
2145
+
2146
+ return 0
2147
+
2148
+ @property
2149
+ def curr_nozzle_temp(self) -> int | None:
2150
+ if self.parameter:
2151
+ return self.parameter.curr_nozzle_temp
2152
+
2153
+ return None
2154
+
2155
+ @property
2156
+ def curr_hotbed_temp(self) -> int | None:
2157
+ if self.parameter:
2158
+ return self.parameter.curr_hotbed_temp
2159
+
2160
+ return None
2161
+
2162
+ def build_mapping_for_material_list(
2163
+ self,
2164
+ slot_index_list: list[int],
2165
+ material_list: list[dict[str, Any]],
2166
+ ) -> list[AnycubicMaterialMapping]:
2167
+ if not self._multi_color_box:
2168
+ return list()
2169
+
2170
+ highest_box = max(slot_index_list) // 4
2171
+
2172
+ if self.connected_ace_units < highest_box + 1:
2173
+ raise AnycubicAPIError(ErrorsGeneral.insufficent_ace_units.format(
2174
+ highest_box + 1
2175
+ ))
2176
+
2177
+ ams_box_mapping = list()
2178
+
2179
+ for mcb in self._multi_color_box:
2180
+
2181
+ ams_box_mapping.extend(
2182
+ mcb.build_mapping_for_material_list(
2183
+ slot_index_list=slot_index_list,
2184
+ material_list=material_list,
2185
+ )
2186
+ )
2187
+
2188
+ return sorted(ams_box_mapping, key=lambda x: x.paint_index)
2189
+
2190
+ async def update_info_from_api(
2191
+ self,
2192
+ with_project: bool = True,
2193
+ ) -> None:
2194
+ if self._id is None:
2195
+ raise AnycubicAPIError(ErrorsGeneral.noid_update_info_from_api)
2196
+
2197
+ await self._api_parent.printer_info_for_id(self._id, self)
2198
+
2199
+ if with_project:
2200
+ self._latest_project = await self._api_parent.get_latest_project(
2201
+ printer_id=self.id,
2202
+ project_to_update=self._latest_project
2203
+ )
2204
+
2205
+ async def request_local_file_list(
2206
+ self,
2207
+ ) -> str | None:
2208
+
2209
+ return await self._api_parent._send_order_list_local_files(
2210
+ self,
2211
+ )
2212
+
2213
+ async def request_udisk_file_list(
2214
+ self,
2215
+ ) -> str | None:
2216
+
2217
+ return await self._api_parent._send_order_list_udisk_files(
2218
+ self,
2219
+ )
2220
+
2221
+ async def delete_local_file(
2222
+ self,
2223
+ file_name: str,
2224
+ ) -> str | None:
2225
+
2226
+ return await self._api_parent._send_order_delete_local_file(
2227
+ self,
2228
+ file_name=file_name,
2229
+ )
2230
+
2231
+ async def delete_udisk_file(
2232
+ self,
2233
+ file_name: str,
2234
+ ) -> str | None:
2235
+
2236
+ return await self._api_parent._send_order_delete_udisk_file(
2237
+ self,
2238
+ file_name=file_name,
2239
+ )
2240
+
2241
+ async def multi_color_box_drying_start(
2242
+ self,
2243
+ duration: int,
2244
+ target_temp: int,
2245
+ box_id: int = 0,
2246
+ ) -> str | None:
2247
+ if self.primary_multi_color_box is None:
2248
+ return None
2249
+
2250
+ return await self._api_parent.multi_color_box_drying_start(
2251
+ self,
2252
+ duration=duration,
2253
+ target_temp=target_temp,
2254
+ box_id=box_id,
2255
+ )
2256
+
2257
+ async def multi_color_box_drying_stop(
2258
+ self,
2259
+ box_id: int = -1,
2260
+ ) -> str | None:
2261
+ if self.primary_multi_color_box is None:
2262
+ return None
2263
+
2264
+ return await self._api_parent.multi_color_box_drying_stop(
2265
+ self,
2266
+ box_id=box_id,
2267
+ )
2268
+
2269
+ async def multi_color_box_set_auto_feed(
2270
+ self,
2271
+ enabled: bool,
2272
+ box_id: int = -1,
2273
+ ) -> str | None:
2274
+ if self.primary_multi_color_box is None:
2275
+ return None
2276
+
2277
+ return await self._api_parent.multi_color_box_set_auto_feed(
2278
+ self,
2279
+ enabled=enabled,
2280
+ box_id=box_id,
2281
+ )
2282
+
2283
+ async def multi_color_box_toggle_auto_feed(
2284
+ self,
2285
+ box_id: int = -1,
2286
+ ) -> str | None:
2287
+ if self.primary_multi_color_box is None:
2288
+ return None
2289
+
2290
+ return await self._api_parent.multi_color_box_toggle_auto_feed(
2291
+ self,
2292
+ box_id=box_id,
2293
+ )
2294
+
2295
+ async def multi_color_box_get_info(self) -> None:
2296
+ return await self._api_parent.multi_color_box_get_info(self)
2297
+
2298
+ async def set_light(
2299
+ self,
2300
+ light_on: bool,
2301
+ brightness: int | None = None,
2302
+ ) -> None:
2303
+ return await self._api_parent.set_printer_light(
2304
+ self,
2305
+ light_on=light_on,
2306
+ brightness=brightness,
2307
+ )
2308
+
2309
+ async def multi_color_box_switch_on_auto_feed(
2310
+ self,
2311
+ box_id: int = -1,
2312
+ ) -> str | None:
2313
+ if self.primary_multi_color_box is None:
2314
+ return None
2315
+
2316
+ return await self._api_parent.multi_color_box_switch_on_auto_feed(
2317
+ self,
2318
+ box_id=box_id,
2319
+ )
2320
+
2321
+ async def multi_color_box_switch_off_auto_feed(
2322
+ self,
2323
+ box_id: int = -1,
2324
+ ) -> str | None:
2325
+ if self.primary_multi_color_box is None:
2326
+ return None
2327
+
2328
+ return await self._api_parent.multi_color_box_switch_off_auto_feed(
2329
+ self,
2330
+ box_id=box_id,
2331
+ )
2332
+
2333
+ async def multi_color_box_set_slot(
2334
+ self,
2335
+ slot_index: int,
2336
+ slot_color: AnycubicMaterialColor | None = None,
2337
+ slot_material_type: str = "PLA",
2338
+ slot_color_red: int | None = None,
2339
+ slot_color_green: int | None = None,
2340
+ slot_color_blue: int | None = None,
2341
+ box_id: int = 0,
2342
+ ) -> str | None:
2343
+ return await self._api_parent.multi_color_box_set_slot(
2344
+ printer=self,
2345
+ slot_index=slot_index,
2346
+ slot_color=slot_color,
2347
+ slot_material_type=slot_material_type,
2348
+ slot_color_red=slot_color_red,
2349
+ slot_color_green=slot_color_green,
2350
+ slot_color_blue=slot_color_blue,
2351
+ box_id=box_id,
2352
+ )
2353
+
2354
+ async def multi_color_box_set_pla_slot(
2355
+ self,
2356
+ slot_index: int,
2357
+ slot_color: AnycubicMaterialColor,
2358
+ box_id: int = 0,
2359
+ ) -> str | None:
2360
+
2361
+ return await self._api_parent.multi_color_box_set_pla_slot(
2362
+ printer=self,
2363
+ slot_index=slot_index,
2364
+ slot_color=slot_color,
2365
+ box_id=box_id,
2366
+ )
2367
+
2368
+ async def multi_color_box_set_petg_slot(
2369
+ self,
2370
+ slot_index: int,
2371
+ slot_color: AnycubicMaterialColor,
2372
+ box_id: int = 0,
2373
+ ) -> str | None:
2374
+
2375
+ return await self._api_parent.multi_color_box_set_petg_slot(
2376
+ printer=self,
2377
+ slot_index=slot_index,
2378
+ slot_color=slot_color,
2379
+ box_id=box_id,
2380
+ )
2381
+
2382
+ async def multi_color_box_set_abs_slot(
2383
+ self,
2384
+ slot_index: int,
2385
+ slot_color: AnycubicMaterialColor,
2386
+ box_id: int = 0,
2387
+ ) -> str | None:
2388
+
2389
+ return await self._api_parent.multi_color_box_set_abs_slot(
2390
+ printer=self,
2391
+ slot_index=slot_index,
2392
+ slot_color=slot_color,
2393
+ box_id=box_id,
2394
+ )
2395
+
2396
+ async def multi_color_box_set_pacf_slot(
2397
+ self,
2398
+ slot_index: int,
2399
+ slot_color: AnycubicMaterialColor,
2400
+ box_id: int = 0,
2401
+ ) -> str | None:
2402
+
2403
+ return await self._api_parent.multi_color_box_set_pacf_slot(
2404
+ printer=self,
2405
+ slot_index=slot_index,
2406
+ slot_color=slot_color,
2407
+ box_id=box_id,
2408
+ )
2409
+
2410
+ async def multi_color_box_set_pc_slot(
2411
+ self,
2412
+ slot_index: int,
2413
+ slot_color: AnycubicMaterialColor,
2414
+ box_id: int = 0,
2415
+ ) -> str | None:
2416
+
2417
+ return await self._api_parent.multi_color_box_set_pc_slot(
2418
+ printer=self,
2419
+ slot_index=slot_index,
2420
+ slot_color=slot_color,
2421
+ box_id=box_id,
2422
+ )
2423
+
2424
+ async def multi_color_box_set_asa_slot(
2425
+ self,
2426
+ slot_index: int,
2427
+ slot_color: AnycubicMaterialColor,
2428
+ box_id: int = 0,
2429
+ ) -> str | None:
2430
+
2431
+ return await self._api_parent.multi_color_box_set_asa_slot(
2432
+ printer=self,
2433
+ slot_index=slot_index,
2434
+ slot_color=slot_color,
2435
+ box_id=box_id,
2436
+ )
2437
+
2438
+ async def multi_color_box_set_hips_slot(
2439
+ self,
2440
+ slot_index: int,
2441
+ slot_color: AnycubicMaterialColor,
2442
+ box_id: int = 0,
2443
+ ) -> str | None:
2444
+
2445
+ return await self._api_parent.multi_color_box_set_hips_slot(
2446
+ printer=self,
2447
+ slot_index=slot_index,
2448
+ slot_color=slot_color,
2449
+ box_id=box_id,
2450
+ )
2451
+
2452
+ async def multi_color_box_set_pa_slot(
2453
+ self,
2454
+ slot_index: int,
2455
+ slot_color: AnycubicMaterialColor,
2456
+ box_id: int = 0,
2457
+ ) -> str | None:
2458
+
2459
+ return await self._api_parent.multi_color_box_set_pa_slot(
2460
+ printer=self,
2461
+ slot_index=slot_index,
2462
+ slot_color=slot_color,
2463
+ box_id=box_id,
2464
+ )
2465
+
2466
+ async def multi_color_box_set_pla_se_slot(
2467
+ self,
2468
+ slot_index: int,
2469
+ slot_color: AnycubicMaterialColor,
2470
+ box_id: int = 0,
2471
+ ) -> str | None:
2472
+
2473
+ return await self._api_parent.multi_color_box_set_pla_se_slot(
2474
+ printer=self,
2475
+ slot_index=slot_index,
2476
+ slot_color=slot_color,
2477
+ box_id=box_id,
2478
+ )
2479
+
2480
+ async def pause_print(
2481
+ self,
2482
+ project: AnycubicProject | None = None,
2483
+ ) -> str | None:
2484
+
2485
+ return await self._api_parent.pause_print(
2486
+ self,
2487
+ project=project,
2488
+ )
2489
+
2490
+ async def resume_print(
2491
+ self,
2492
+ project: AnycubicProject | None = None,
2493
+ ) -> str | None:
2494
+
2495
+ return await self._api_parent.resume_print(
2496
+ self,
2497
+ project=project,
2498
+ )
2499
+
2500
+ async def cancel_print(
2501
+ self,
2502
+ project: AnycubicProject | None = None,
2503
+ ) -> str | None:
2504
+
2505
+ return await self._api_parent.cancel_print(
2506
+ self,
2507
+ project=project,
2508
+ )
2509
+
2510
+ async def multi_color_box_feed_filament(
2511
+ self,
2512
+ slot_index: int,
2513
+ box_id: int = -1,
2514
+ finish: bool = False,
2515
+ ) -> str | None:
2516
+
2517
+ return await self._api_parent.multi_color_box_feed_filament(
2518
+ self,
2519
+ slot_index=slot_index,
2520
+ box_id=box_id,
2521
+ finish=finish,
2522
+ )
2523
+
2524
+ async def multi_color_box_retract_filament(
2525
+ self,
2526
+ box_id: int = -1,
2527
+ ) -> str | None:
2528
+
2529
+ return await self._api_parent.multi_color_box_retract_filament(
2530
+ self,
2531
+ box_id=box_id,
2532
+ )
2533
+
2534
+ async def update_printer_firmware(
2535
+ self,
2536
+ ) -> str | None:
2537
+
2538
+ return await self._api_parent.update_printer_firmware(
2539
+ self,
2540
+ )
2541
+
2542
+ async def update_printer_multi_color_box_firmware(
2543
+ self,
2544
+ box_id: int = -1,
2545
+ ) -> str | None:
2546
+
2547
+ return await self._api_parent.update_printer_multi_color_box_firmware(
2548
+ self,
2549
+ box_id=box_id,
2550
+ )
2551
+
2552
+ async def update_printer_all_multi_color_box_firmware(
2553
+ self,
2554
+ ) -> list[str | None] | None:
2555
+
2556
+ return await self._api_parent.update_printer_all_multi_color_box_firmware(
2557
+ self,
2558
+ )
2559
+
2560
+ async def print_with_cloud_file_id(
2561
+ self,
2562
+ cloud_file_id: int,
2563
+ ams_box_mapping: list[AnycubicMaterialMapping] | None = None,
2564
+ temp_file: bool = False,
2565
+ ) -> str | None:
2566
+ return await self._api_parent.print_with_cloud_file_id(
2567
+ printer=self,
2568
+ cloud_file_id=cloud_file_id,
2569
+ ams_box_mapping=ams_box_mapping,
2570
+ temp_file=temp_file,
2571
+ )
2572
+
2573
+ async def print_with_cloud_gcode_id(
2574
+ self,
2575
+ gcode_id: int,
2576
+ slot_index_list: list[int] | None = None,
2577
+ ) -> AnycubicPrintResponse:
2578
+ return await self._api_parent.print_with_cloud_gcode_id(
2579
+ printer=self,
2580
+ gcode_id=gcode_id,
2581
+ slot_index_list=slot_index_list,
2582
+ )
2583
+
2584
+ async def print_and_upload_save_in_cloud(
2585
+ self,
2586
+ full_file_path: str | None = None,
2587
+ file_name: str | None = None,
2588
+ file_bytes: bytes | None = None,
2589
+ slot_index_list: list[int] | None = None,
2590
+ ) -> AnycubicPrintResponse:
2591
+ return await self._api_parent.print_and_upload_save_in_cloud(
2592
+ printer=self,
2593
+ full_file_path=full_file_path,
2594
+ file_name=file_name,
2595
+ file_bytes=file_bytes,
2596
+ slot_index_list=slot_index_list,
2597
+ )
2598
+
2599
+ async def print_and_upload_no_cloud_save(
2600
+ self,
2601
+ full_file_path: str | None = None,
2602
+ file_name: str | None = None,
2603
+ file_bytes: bytes | None = None,
2604
+ slot_index_list: list[int] | None = None,
2605
+ ) -> AnycubicPrintResponse:
2606
+ return await self._api_parent.print_and_upload_no_cloud_save(
2607
+ printer=self,
2608
+ full_file_path=full_file_path,
2609
+ file_name=file_name,
2610
+ file_bytes=file_bytes,
2611
+ slot_index_list=slot_index_list,
2612
+ )
2613
+
2614
+ async def change_print_setting_speed_mode(
2615
+ self,
2616
+ new_speed: int
2617
+ ) -> str | None:
2618
+ return await self._api_parent._send_order_change_print_settings(
2619
+ printer=self,
2620
+ print_settings=AnycubicPrintingSettings(
2621
+ print_speed_mode=new_speed,
2622
+ ),
2623
+ )
2624
+
2625
+ async def change_print_setting_target_nozzle_temp(
2626
+ self,
2627
+ new_temperature: int
2628
+ ) -> str | None:
2629
+ return await self._api_parent._send_order_change_print_settings(
2630
+ printer=self,
2631
+ print_settings=AnycubicPrintingSettings(
2632
+ target_nozzle_temp=new_temperature,
2633
+ ),
2634
+ )
2635
+
2636
+ async def change_print_setting_target_hotbed_temp(
2637
+ self,
2638
+ new_temperature: int
2639
+ ) -> str | None:
2640
+ return await self._api_parent._send_order_change_print_settings(
2641
+ printer=self,
2642
+ print_settings=AnycubicPrintingSettings(
2643
+ target_hotbed_temp=new_temperature,
2644
+ ),
2645
+ )
2646
+
2647
+ async def change_print_setting_fan_speed_pct(
2648
+ self,
2649
+ new_pct: int
2650
+ ) -> str | None:
2651
+ return await self._api_parent._send_order_change_print_settings(
2652
+ printer=self,
2653
+ print_settings=AnycubicPrintingSettings(
2654
+ fan_speed_pct=new_pct,
2655
+ ),
2656
+ )
2657
+
2658
+ async def change_print_setting_aux_fan_speed_pct(
2659
+ self,
2660
+ new_pct: int
2661
+ ) -> str | None:
2662
+ return await self._api_parent._send_order_change_print_settings(
2663
+ printer=self,
2664
+ print_settings=AnycubicPrintingSettings(
2665
+ aux_fan_speed_pct=new_pct,
2666
+ ),
2667
+ )
2668
+
2669
+ async def change_print_setting_box_fan_level(
2670
+ self,
2671
+ new_level: int
2672
+ ) -> str | None:
2673
+ return await self._api_parent._send_order_change_print_settings(
2674
+ printer=self,
2675
+ print_settings=AnycubicPrintingSettings(
2676
+ box_fan_level=new_level,
2677
+ ),
2678
+ )
2679
+
2680
+ async def change_print_setting_bottom_layers(
2681
+ self,
2682
+ new_layers: int
2683
+ ) -> str | None:
2684
+ return await self._api_parent._send_order_change_print_settings(
2685
+ printer=self,
2686
+ print_settings=AnycubicPrintingSettings(
2687
+ bottom_layers=new_layers,
2688
+ ),
2689
+ )
2690
+
2691
+ async def change_print_setting_bottom_time(
2692
+ self,
2693
+ new_time: float
2694
+ ) -> str | None:
2695
+ return await self._api_parent._send_order_change_print_settings(
2696
+ printer=self,
2697
+ print_settings=AnycubicPrintingSettings(
2698
+ bottom_time=new_time,
2699
+ ),
2700
+ )
2701
+
2702
+ async def change_print_setting_off_time(
2703
+ self,
2704
+ new_time: float
2705
+ ) -> str | None:
2706
+ return await self._api_parent._send_order_change_print_settings(
2707
+ printer=self,
2708
+ print_settings=AnycubicPrintingSettings(
2709
+ off_time=new_time,
2710
+ ),
2711
+ )
2712
+
2713
+ async def change_print_setting_on_time(
2714
+ self,
2715
+ new_time: float
2716
+ ) -> str | None:
2717
+ return await self._api_parent._send_order_change_print_settings(
2718
+ printer=self,
2719
+ print_settings=AnycubicPrintingSettings(
2720
+ on_time=new_time,
2721
+ ),
2722
+ )
2723
+
2724
+ async def query_printer_options(
2725
+ self,
2726
+ project: AnycubicProject | None = None,
2727
+ ) -> None:
2728
+ return await self._api_parent.query_printer_options(
2729
+ printer=self,
2730
+ project=project,
2731
+ )
2732
+
2733
+ def __repr__(self) -> str:
2734
+ if self._id is None:
2735
+ return f"AnycubicPrinter(machine_type={self._machine_type}, machine_name={self._machine_name})"
2736
+ else:
2737
+ return (
2738
+ f"AnycubicPrinter(machine_type={self._machine_type}, machine_name={self._machine_name},\n "
2739
+ f"id={self.id}, name={self.name}, key={self.key}, printer_type={self.printer_type}, status={self.status}, "
2740
+ f"available={self.available},\n "
2741
+ f"device_status={self.device_status}, printer_online={self.printer_online}, ready_status={self.ready_status}, "
2742
+ f"is_printing={self.is_printing}, reason={self.reason},\n "
2743
+ f"machine_data=\n{self.machine_data},\n "
2744
+ f"parameter=\n{self.parameter},\n "
2745
+ f"fw_version=\n{self.fw_version},\n "
2746
+ f"color=\n{self.color},\n "
2747
+ f"tools=\n{self.tools},\n "
2748
+ f"multi_color_box_fw_version=\n{self.multi_color_box_fw_version},\n "
2749
+ f"external_shelves=\n{self.external_shelves},\n "
2750
+ f"multi_color_box=\n{self.multi_color_box},\n "
2751
+ f"primary_drying_status=\n{self.primary_drying_status},\n "
2752
+ f"secondary_drying_status=\n{self.secondary_drying_status},\n "
2753
+ f")")