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,1107 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from ..exceptions.error_strings import ErrorsDataParsing
6
+ from ..exceptions.exceptions import AnycubicDataParsingError
7
+
8
+
9
+ class AnycubicMaterialMapping:
10
+ __slots__ = (
11
+ "_spool_index",
12
+ "_filament_used",
13
+ "_material_type",
14
+ "_color_red",
15
+ "_color_green",
16
+ "_color_blue",
17
+ "_paint_index",
18
+ )
19
+
20
+ def __init__(
21
+ self,
22
+ spool_index: int,
23
+ filament_used: float,
24
+ material_type: str,
25
+ color_red: int,
26
+ color_green: int,
27
+ color_blue: int,
28
+ paint_index: int = 0,
29
+ ) -> None:
30
+ self._spool_index = int(spool_index)
31
+ self._filament_used = float(filament_used)
32
+ self._material_type = str(material_type)
33
+ self._color_red = int(color_red)
34
+ self._color_green = int(color_green)
35
+ self._color_blue = int(color_blue)
36
+ self._paint_index = int(paint_index)
37
+
38
+ @property
39
+ def spool_index(self) -> int:
40
+ return self._spool_index
41
+
42
+ @property
43
+ def filament_used(self) -> float:
44
+ return self._filament_used
45
+
46
+ @property
47
+ def material_type(self) -> str:
48
+ return self._material_type
49
+
50
+ @property
51
+ def paint_index(self) -> int:
52
+ return self._paint_index
53
+
54
+ @property
55
+ def color_data(self) -> list[int]:
56
+ return list([
57
+ self._color_red,
58
+ self._color_green,
59
+ self._color_blue,
60
+ ])
61
+
62
+ def as_box_mapping_data(self) -> dict[str, Any]:
63
+ return {
64
+ 'ams_color': self.color_data,
65
+ 'ams_index': self._spool_index,
66
+ 'filament_used': self._filament_used,
67
+ 'material_type': self._material_type,
68
+ 'paint_color': self.color_data,
69
+ 'paint_index': self._paint_index,
70
+ }
71
+
72
+ def __repr__(self) -> str:
73
+ return (
74
+ f"AnycubicMaterialMapping("
75
+ f"spool_index={self._spool_index}, "
76
+ f"filament_used={self._filament_used}, "
77
+ f"material_type={self._material_type}, "
78
+ f"color_red={self._color_red}, "
79
+ f"color_green={self._color_green}, "
80
+ f"color_blue={self._color_blue}, "
81
+ f"paint_index={self._paint_index})"
82
+ )
83
+
84
+
85
+ class AnycubicMaterialColor:
86
+ __slots__ = (
87
+ "_red",
88
+ "_green",
89
+ "_blue",
90
+ )
91
+
92
+ def __init__(
93
+ self,
94
+ red: int,
95
+ green: int,
96
+ blue: int,
97
+ ) -> None:
98
+ self._red: int = red
99
+ self._green: int = green
100
+ self._blue: int = blue
101
+
102
+ @property
103
+ def red(self) -> int:
104
+ return self._red
105
+
106
+ @property
107
+ def green(self) -> int:
108
+ return self._green
109
+
110
+ @property
111
+ def blue(self) -> int:
112
+ return self._blue
113
+
114
+ @property
115
+ def data(self) -> list[int]:
116
+ return list([
117
+ self._red,
118
+ self._green,
119
+ self._blue,
120
+ ])
121
+
122
+ def __repr__(self) -> str:
123
+ return (
124
+ f"AnycubicMaterialColor("
125
+ f"red={self._red}, "
126
+ f"green={self._green}, "
127
+ f"blue={self._blue})"
128
+ )
129
+
130
+
131
+ # class AnycubicMachineBaseInfo:
132
+ # def __init__(
133
+ # self,
134
+ # print_count: int,
135
+ # print_totaltime: str,
136
+ # material_type: str,
137
+ # material_used: str,
138
+ # description: str,
139
+ # create_time: int,
140
+ # firmware_version: str,
141
+ # machine_mac: str,
142
+ # ) -> None:
143
+ # self._print_count: int = int(print_count)
144
+ # self._print_totaltime: str = str(print_totaltime)
145
+ # self._material_type: str = str(material_type)
146
+ # self._material_used: str = str(material_used)
147
+ # self._description: str = str(description)
148
+ # self._create_time: int = int(create_time)
149
+ # self._firmware_version = str(firmware_version)
150
+ # self._machine_mac: str = str(machine_mac)
151
+
152
+ # @classmethod
153
+ # def from_json(cls, data: dict[str, Any] | None) -> AnycubicMachineBaseInfo | None:
154
+ # if data is None:
155
+ # return None
156
+
157
+ # return cls(
158
+ # print_count=data['print_count'],
159
+ # print_totaltime=data['print_totaltime'],
160
+ # material_type=data['material_type'],
161
+ # material_used=data['material_used'],
162
+ # description=data['description'],
163
+ # create_time=data['create_time'],
164
+ # firmware_version=data['firmware_version'],
165
+ # machine_mac=data['machine_mac'],
166
+ # )
167
+
168
+ # def __repr__(self) -> str:
169
+ # return (
170
+ # f"AnycubicMachineBaseInfo(print_count={self._print_count}, print_totaltime={self._print_totaltime}, "
171
+ # f"material_type={self._material_type}, material_used={self._material_used},"
172
+ # f"description={self._description}, create_time={self._create_time}, firmware_version={self._firmware_version}, "
173
+ # f"machine_mac={self._machine_mac})"
174
+ # )
175
+
176
+
177
+ class AnycubicMachineToolInfo:
178
+ __slots__ = (
179
+ "_id",
180
+ "_typd_id",
181
+ "_model_id",
182
+ "_type_function_id",
183
+ "_parent_id",
184
+ "_function_name",
185
+ "_function_des",
186
+ "_control",
187
+ "_param",
188
+ "_icon_url",
189
+ "_function_type",
190
+ "_status",
191
+ "_show_place",
192
+ )
193
+
194
+ def __init__(
195
+ self,
196
+ id: int,
197
+ typd_id: int,
198
+ model_id: int,
199
+ type_function_id: int,
200
+ parent_id: int,
201
+ function_name: str,
202
+ function_des: str,
203
+ control: int,
204
+ param: Any,
205
+ icon_url: str,
206
+ function_type: int,
207
+ status: int,
208
+ show_place: int,
209
+ ) -> None:
210
+ self._id = int(id)
211
+ self._typd_id = int(typd_id)
212
+ self._model_id = int(model_id)
213
+ self._type_function_id = int(type_function_id)
214
+ self._parent_id = int(parent_id)
215
+ self._function_name = str(function_name)
216
+ self._function_des = str(function_des)
217
+ self._control = int(control)
218
+ self._param = param
219
+ self._icon_url = str(icon_url)
220
+ self._function_type = int(function_type)
221
+ self._status = int(status)
222
+ self._show_place = int(show_place)
223
+
224
+ @classmethod
225
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicMachineToolInfo | None:
226
+ if data is None:
227
+ return None
228
+
229
+ return cls(
230
+ id=data['id'],
231
+ typd_id=data['typd_id'],
232
+ model_id=data['model_id'],
233
+ type_function_id=data['type_function_id'],
234
+ parent_id=data['parent_id'],
235
+ function_name=data['function_name'],
236
+ function_des=data['function_des'],
237
+ control=data['control'],
238
+ param=data['param'],
239
+ icon_url=data['icon_url'],
240
+ function_type=data['function_type'],
241
+ status=data['status'],
242
+ show_place=data['show_place'],
243
+ )
244
+
245
+ def __repr__(self) -> str:
246
+ return (
247
+ f"AnycubicMachineToolInfo(id={self._id}, typd_id={self._typd_id}, model_id={self._model_id}, "
248
+ f"type_function_id={self._type_function_id}, parent_id={self._parent_id},\n "
249
+ f"function_name={self._function_name}, function_des={self._function_des}, control={self._control}, "
250
+ f"param={self._param}, icon_url={self._icon_url},\n "
251
+ f"function_type={self._function_type}, status={self._status}, show_place={self._show_place})"
252
+ )
253
+
254
+
255
+ class AnycubicMachineExternalShelves:
256
+ __slots__ = (
257
+ "_id",
258
+ "_type",
259
+ "_color",
260
+ "_loaded",
261
+ "_status_type",
262
+ "_current_status",
263
+ )
264
+
265
+ def __init__(
266
+ self,
267
+ id: int,
268
+ type: str,
269
+ color: list[int],
270
+ loaded: int,
271
+ status_type: int,
272
+ current_status: int,
273
+ ) -> None:
274
+ self._id = int(id)
275
+ self._type = str(type)
276
+ self._color = list([
277
+ int(x) for x in color
278
+ ])
279
+ self._loaded = int(loaded)
280
+ self._status_type = int(status_type)
281
+ self._current_status = int(current_status)
282
+
283
+ @classmethod
284
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicMachineExternalShelves | None:
285
+ if data is None:
286
+ return None
287
+
288
+ return cls(
289
+ id=data['id'],
290
+ type=data['type'],
291
+ color=data['color'],
292
+ loaded=data.get('loaded', False),
293
+ status_type=data.get('status_type', False),
294
+ current_status=data.get('current_status', False),
295
+ )
296
+
297
+ def update_with_mqtt_data(self, data: dict[str, Any] | None) -> None:
298
+ if data is None:
299
+ return None
300
+
301
+ self._type = data['type']
302
+ self._color = data['color']
303
+ self._loaded = data['loaded']
304
+ self._status_type = data['status_type']
305
+ self._current_status = data['current_status']
306
+
307
+ def __repr__(self) -> str:
308
+ return (
309
+ f"AnycubicMachineExternalShelves(id={self._id}, type={self._type}, color={self._color}, loaded={self._loaded}, "
310
+ f"status_type={self._status_type}, current_status={self._current_status})"
311
+ )
312
+
313
+
314
+ class AnycubicFeedStatus:
315
+ __slots__ = (
316
+ "_code",
317
+ "_type",
318
+ "_current_status",
319
+ "_slot_index",
320
+ )
321
+
322
+ def __init__(
323
+ self,
324
+ code: int,
325
+ type: int,
326
+ current_status: int,
327
+ slot_index: int,
328
+ ) -> None:
329
+ self._code = int(code)
330
+ self._type = int(type)
331
+ self._current_status = int(current_status)
332
+ self._slot_index = int(slot_index)
333
+
334
+ @classmethod
335
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicFeedStatus | None:
336
+ if data is None:
337
+ return None
338
+
339
+ return cls(
340
+ code=data.get('code', -1),
341
+ type=data['type'],
342
+ current_status=data['current_status'],
343
+ slot_index=data['slot_index'],
344
+ )
345
+
346
+ @property
347
+ def info_object(self) -> dict[str, Any]:
348
+ return {
349
+ "code": self._code,
350
+ "type": self._type,
351
+ "current_status": self._current_status,
352
+ # -1 when nothing is feeding; otherwise the 1-based slot.
353
+ "slot": self._slot_index + 1 if self._slot_index >= 0 else None,
354
+ }
355
+
356
+ def __repr__(self) -> str:
357
+ return (
358
+ f"AnycubicFeedStatus(code={self._code}, type={self._type}, current_status={self._current_status}, "
359
+ f"slot_index={self._slot_index})"
360
+ )
361
+
362
+
363
+ class AnycubicDryingStatus:
364
+ __slots__ = (
365
+ "_status",
366
+ "_target_temp",
367
+ "_duration",
368
+ "_remain_time",
369
+ )
370
+
371
+ def __init__(
372
+ self,
373
+ status: int,
374
+ target_temp: int,
375
+ duration: int,
376
+ remain_time: int,
377
+ ) -> None:
378
+ self._status = int(status)
379
+ self._target_temp = int(target_temp)
380
+ self._duration = int(duration)
381
+ self._remain_time = int(remain_time)
382
+
383
+ @classmethod
384
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicDryingStatus | None:
385
+ if data is None:
386
+ return None
387
+
388
+ return cls(
389
+ status=data['status'],
390
+ target_temp=data.get('target_temp', 0),
391
+ duration=data.get('duration', 0),
392
+ remain_time=data.get('remain_time', 0),
393
+ )
394
+
395
+ @property
396
+ def is_drying(self) -> bool:
397
+ return self._status == 1
398
+
399
+ @property
400
+ def raw_status_code(self) -> int:
401
+ return self._status
402
+
403
+ @property
404
+ def target_temperature(self) -> int:
405
+ return self._target_temp if self.is_drying else 0
406
+
407
+ @property
408
+ def total_duration(self) -> int:
409
+ return self._duration if self.is_drying else 0
410
+
411
+ @property
412
+ def remaining_time(self) -> int:
413
+ return self._remain_time if self.is_drying else 0
414
+
415
+ def __repr__(self) -> str:
416
+ return (
417
+ f"AnycubicDryingStatus(is_drying={self.is_drying}, status={self._status}, target_temp={self._target_temp}, "
418
+ f"duration={self._duration}, remain_time={self._remain_time})"
419
+ )
420
+
421
+
422
+ class AnycubicSpoolInfo:
423
+ __slots__ = (
424
+ "_index",
425
+ "_sku",
426
+ "_material_type",
427
+ "_color",
428
+ "_color_group",
429
+ "_edit_status",
430
+ "_status",
431
+ "_icon_type",
432
+ "_consumables_percent",
433
+ )
434
+
435
+ def __init__(
436
+ self,
437
+ index: int,
438
+ sku: str,
439
+ material_type: str,
440
+ color: list[int],
441
+ edit_status: int,
442
+ status: int,
443
+ color_group: list[list[int]] | None = None,
444
+ icon_type: int | None = None,
445
+ consumables_percent: float | None = None,
446
+ ) -> None:
447
+ self._index = int(index)
448
+ self._sku = str(sku)
449
+ self._material_type = str(material_type)
450
+ self._color = list([
451
+ int(x) for x in color
452
+ ])
453
+ # Every colour on the spool, as RGBA. Single-colour filament reports one
454
+ # entry matching `color`; multi-colour / gradient spools report several.
455
+ self._color_group: list[list[int]] = list([
456
+ list([int(c) for c in entry]) for entry in (color_group or [])
457
+ ])
458
+ self._edit_status = int(edit_status)
459
+ self._status = int(status)
460
+ self._icon_type = int(icon_type) if icon_type is not None else None
461
+ self._consumables_percent = (
462
+ float(consumables_percent) if consumables_percent is not None else None
463
+ )
464
+
465
+ @classmethod
466
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicSpoolInfo | None:
467
+ if data is None:
468
+ return None
469
+
470
+ return cls(
471
+ index=data['index'],
472
+ sku=data['sku'],
473
+ material_type=data['type'],
474
+ color=data['color'],
475
+ edit_status=data['edit_status'],
476
+ status=data['status'],
477
+ color_group=data.get('color_group'),
478
+ icon_type=data.get('icon_type'),
479
+ consumables_percent=data.get('consumables_percent'),
480
+ )
481
+
482
+ @property
483
+ def slot_index(self) -> int:
484
+ return self._index
485
+
486
+ @property
487
+ def sku(self) -> str:
488
+ return self._sku
489
+
490
+ @property
491
+ def material_type(self) -> str:
492
+ return self._material_type
493
+
494
+ @property
495
+ def color(self) -> list[int]:
496
+ return self._color
497
+
498
+ @property
499
+ def color_hex(self) -> str:
500
+ """Slot colour as #RRGGBB, for dashboard cards and templates."""
501
+ return "#{:02X}{:02X}{:02X}".format(*self._color[:3])
502
+
503
+ @property
504
+ def color_group(self) -> list[list[int]]:
505
+ """Every colour on the spool as RGBA. Several entries for multi-colour."""
506
+ return self._color_group
507
+
508
+ @property
509
+ def colors_hex(self) -> list[str]:
510
+ """Every colour on the spool as #RRGGBB, in order."""
511
+ if not self._color_group:
512
+ return [self.color_hex]
513
+
514
+ return [
515
+ "#{:02X}{:02X}{:02X}".format(*entry[:3])
516
+ for entry in self._color_group
517
+ if len(entry) >= 3
518
+ ]
519
+
520
+ @property
521
+ def is_multi_color(self) -> bool:
522
+ return len(self._color_group) > 1
523
+
524
+ @property
525
+ def edit_status(self) -> int:
526
+ return self._edit_status
527
+
528
+ @property
529
+ def icon_type(self) -> int | None:
530
+ return self._icon_type
531
+
532
+ @property
533
+ def consumables_percent(self) -> float | None:
534
+ return self._consumables_percent
535
+
536
+ @property
537
+ def color_red(self) -> int:
538
+ return self._color[0]
539
+
540
+ @property
541
+ def color_green(self) -> int:
542
+ return self._color[1]
543
+
544
+ @property
545
+ def color_blue(self) -> int:
546
+ return self._color[2]
547
+
548
+ @property
549
+ def status(self) -> int:
550
+ return self._status
551
+
552
+ @property
553
+ def spool_loaded(self) -> bool:
554
+ return self._status == 5
555
+
556
+ def set_spool_loaded(self, is_loaded: bool) -> None:
557
+ if is_loaded:
558
+ self._status = 5
559
+ else:
560
+ self._status = 4
561
+
562
+ def __repr__(self) -> str:
563
+ return (
564
+ f"AnycubicSpoolInfo(index={self._index}, sku={self._sku}, material_type={self.material_type}, color={self._color}, "
565
+ f"edit_status={self._edit_status}, status={self._status})"
566
+ )
567
+
568
+
569
+ class AnycubicMultiColorBox:
570
+ __slots__ = (
571
+ "_id",
572
+ "_status",
573
+ "_model_id",
574
+ "_auto_feed",
575
+ "_loaded_slot",
576
+ "_feed_status",
577
+ "_temp",
578
+ "_humidity",
579
+ "_drying_status",
580
+ "_curr_nozzle_temp",
581
+ "_target_nozzle_temp",
582
+ "_slots",
583
+ )
584
+
585
+ def __init__(
586
+ self,
587
+ id: int,
588
+ status: int,
589
+ model_id: int,
590
+ auto_feed: int,
591
+ loaded_slot: int,
592
+ feed_status: dict[str, Any] | None,
593
+ temp: int,
594
+ drying_status: dict[str, Any] | None,
595
+ curr_nozzle_temp: int | None,
596
+ target_nozzle_temp: int | None,
597
+ slots: list[dict[str, Any]],
598
+ humidity: float | None = None,
599
+ ) -> None:
600
+ self._id: int = int(id)
601
+ self._status: int = int(status)
602
+ self._model_id: int = int(model_id)
603
+ self._auto_feed: int = int(auto_feed)
604
+ self._loaded_slot: int = int(loaded_slot)
605
+ self.set_feed_status(feed_status)
606
+ self.set_current_temperature(temp)
607
+ self._humidity: float | None = (
608
+ float(humidity) if humidity is not None else None
609
+ )
610
+ self.set_drying_status(drying_status)
611
+ self._curr_nozzle_temp: int | None = int(curr_nozzle_temp) if curr_nozzle_temp is not None else None
612
+ self._target_nozzle_temp: int | None = int(target_nozzle_temp) if target_nozzle_temp is not None else None
613
+ self._slots: list[AnycubicSpoolInfo] = list()
614
+ for x in slots:
615
+ if spool := AnycubicSpoolInfo.from_json(x):
616
+ self._slots.append(spool)
617
+ else:
618
+ raise AnycubicDataParsingError(ErrorsDataParsing.ace.format(slots))
619
+
620
+ def set_auto_feed(self, auto_feed: int) -> None:
621
+ self._auto_feed = int(auto_feed)
622
+
623
+ def set_drying_status(self, drying_status: dict[str, Any] | None) -> None:
624
+ self._drying_status = AnycubicDryingStatus.from_json(drying_status)
625
+
626
+ def set_feed_status(self, feed_status: dict[str, Any] | None) -> None:
627
+ self._feed_status = AnycubicFeedStatus.from_json(feed_status)
628
+
629
+ def set_slot_loaded(self, slot_num: int) -> None:
630
+ self._loaded_slot = slot_num
631
+
632
+ def set_current_temperature(self, temp: int) -> None:
633
+ self._temp = int(temp)
634
+
635
+ def update_slots_with_mqtt_data(self, slot_list: list[dict[str, Any]] | None) -> None:
636
+ if slot_list is None:
637
+ return
638
+
639
+ for slot in slot_list:
640
+ slot_index = slot['index']
641
+ if spool := AnycubicSpoolInfo.from_json(slot):
642
+ self._slots[slot_index] = spool
643
+ else:
644
+ raise AnycubicDataParsingError(ErrorsDataParsing.ace.format(slot_list))
645
+
646
+ def build_mapping_for_material_list(
647
+ self,
648
+ slot_index_list: list[int],
649
+ material_list: list[dict[str, Any]],
650
+ ) -> list[AnycubicMaterialMapping]:
651
+ box_slots = self.slots
652
+ ams_box_mapping = list()
653
+
654
+ for x, mat_conf in enumerate(material_list):
655
+ slot_index = slot_index_list[x]
656
+ spool_index = slot_index
657
+ slot_index = slot_index - (4 * self.box_id)
658
+
659
+ if slot_index < 0 or slot_index > 3:
660
+ continue
661
+
662
+ ams_slot = box_slots[slot_index]
663
+ material = AnycubicMaterialMapping(
664
+ spool_index=spool_index,
665
+ filament_used=mat_conf['filament_used'],
666
+ material_type=mat_conf['material_type'],
667
+ color_red=ams_slot.color_red,
668
+ color_green=ams_slot.color_green,
669
+ color_blue=ams_slot.color_blue,
670
+ paint_index=mat_conf['paint_index'],
671
+ )
672
+ ams_box_mapping.append(material)
673
+
674
+ return ams_box_mapping
675
+
676
+ @classmethod
677
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicMultiColorBox | None:
678
+ if data is None:
679
+ return None
680
+
681
+ return cls(
682
+ id=data['id'],
683
+ status=data['status'],
684
+ model_id=data['model_id'],
685
+ auto_feed=data['auto_feed'],
686
+ loaded_slot=data['loaded_slot'],
687
+ feed_status=data['feed_status'],
688
+ temp=data['temp'],
689
+ humidity=data.get('humidity'),
690
+ drying_status=data['drying_status'],
691
+ curr_nozzle_temp=data.get('curr_nozzle_temp'),
692
+ target_nozzle_temp=data.get('target_nozzle_temp'),
693
+ slots=data['slots'],
694
+ )
695
+
696
+ @property
697
+ def current_temperature(self) -> int:
698
+ return self._temp
699
+
700
+ @property
701
+ def model_id(self) -> int:
702
+ return self._model_id
703
+
704
+ @property
705
+ def box_info_object(self) -> dict[str, Any]:
706
+ return {
707
+ "box_id": self._id,
708
+ "model_id": self._model_id,
709
+ "status": self._status,
710
+ "temperature": self._temp,
711
+ "humidity": self._humidity,
712
+ "auto_feed": bool(self._auto_feed),
713
+ "loaded_slot": self._loaded_slot + 1 if self._loaded_slot >= 0 else None,
714
+ "feed_status": (
715
+ self._feed_status.info_object if self._feed_status else None
716
+ ),
717
+ }
718
+
719
+ @property
720
+ def humidity(self) -> float | None:
721
+ """ACE internal humidity. Reads 0 on hardware without the sensor."""
722
+ return self._humidity
723
+
724
+ @property
725
+ def loaded_slot(self) -> int:
726
+ """Index of the slot currently feeding, or -1 when none is loaded."""
727
+ return self._loaded_slot
728
+
729
+ @property
730
+ def box_id(self) -> int:
731
+ return self._id
732
+
733
+ @property
734
+ def auto_feed(self) -> int:
735
+ return self._auto_feed
736
+
737
+ @property
738
+ def slots(self) -> list[AnycubicSpoolInfo]:
739
+ return self._slots
740
+
741
+ @property
742
+ def total_slots(self) -> int:
743
+ return len(self._slots)
744
+
745
+ @property
746
+ def drying_status(self) -> AnycubicDryingStatus | None:
747
+ return self._drying_status
748
+
749
+ @property
750
+ def spool_info_object(self) -> list[dict[str, Any]] | None:
751
+ if not self._slots or len(self._slots) < 1:
752
+ return None
753
+
754
+ spool_list = list([
755
+ {
756
+ "slot": slot.slot_index + 1,
757
+ "material_type": slot.material_type,
758
+ "color": slot.color,
759
+ "color_hex": slot.color_hex,
760
+ "colors_hex": slot.colors_hex,
761
+ "color_group": slot.color_group,
762
+ "is_multi_color": slot.is_multi_color,
763
+ "sku": slot.sku,
764
+ "status": slot.status,
765
+ "spool_loaded": slot.spool_loaded,
766
+ "edit_status": slot.edit_status,
767
+ "icon_type": slot.icon_type,
768
+ "consumables_percent": slot.consumables_percent,
769
+ } for slot in self._slots
770
+ ])
771
+ return spool_list
772
+
773
+ def __repr__(self) -> str:
774
+ return (
775
+ f"AnycubicMultiColorBox(id={self._id}, status={self._status}, model_id={self._model_id}, auto_feed={self._auto_feed}, "
776
+ f"loaded_slot={self._loaded_slot},\n "
777
+ f"temp={self._temp}, curr_nozzle_temp={self._curr_nozzle_temp}, target_nozzle_temp={self._target_nozzle_temp},\n "
778
+ f"feed_status={self._feed_status},\n "
779
+ f"drying_status={self._drying_status},\n "
780
+ f"slots={self._slots})"
781
+ )
782
+
783
+
784
+ class AnycubicMachineData:
785
+ __slots__ = (
786
+ "_name",
787
+ "_pixel",
788
+ "_res_x",
789
+ "_res_y",
790
+ "_format",
791
+ "_size_x",
792
+ "_size_y",
793
+ "_size_z",
794
+ "_suffix",
795
+ "_anti_max",
796
+ )
797
+
798
+ def __init__(
799
+ self,
800
+ name: str,
801
+ pixel: float,
802
+ res_x: int,
803
+ res_y: int,
804
+ format: str,
805
+ size_x: float,
806
+ size_y: float,
807
+ size_z: float,
808
+ suffix: str,
809
+ anti_max: int,
810
+ ) -> None:
811
+ self._name = str(name)
812
+ self._pixel = float(pixel)
813
+ self._res_x = int(res_x)
814
+ self._res_y = int(res_y)
815
+ self._format = str(format)
816
+ self._size_x = float(size_x)
817
+ self._size_y = float(size_y)
818
+ self._size_z = float(size_z)
819
+ self._suffix = str(suffix)
820
+ self._anti_max = int(anti_max)
821
+
822
+ @classmethod
823
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicMachineData | None:
824
+ if data is None:
825
+ return None
826
+
827
+ return cls(
828
+ name=data['name'],
829
+ pixel=data['pixel'],
830
+ res_x=data['res_x'],
831
+ res_y=data['res_y'],
832
+ format=data['format'],
833
+ size_x=data['size_x'],
834
+ size_y=data['size_y'],
835
+ size_z=data['size_z'],
836
+ suffix=data['suffix'],
837
+ anti_max=data['anti_max'],
838
+ )
839
+
840
+ def __repr__(self) -> str:
841
+ return (
842
+ f"AnycubicMachineData(name={self._name}, pixel={self._pixel}, format={self._format}, suffix={self._suffix},\n "
843
+ f"res_x={self._res_x}, res_y={self._res_y}, size_x={self._size_x}, size_y={self._size_y}, size_z={self._size_z}, "
844
+ f"anti_max={self._anti_max})"
845
+ )
846
+
847
+
848
+ class AnycubicMachineParameter:
849
+ __slots__ = (
850
+ "_curr_hotbed_temp",
851
+ "_curr_nozzle_temp",
852
+ )
853
+
854
+ def __init__(
855
+ self,
856
+ curr_hotbed_temp: int,
857
+ curr_nozzle_temp: int,
858
+ ) -> None:
859
+ self._curr_hotbed_temp = int(curr_hotbed_temp)
860
+ self._curr_nozzle_temp = int(curr_nozzle_temp)
861
+
862
+ @property
863
+ def curr_hotbed_temp(self) -> int:
864
+ return self._curr_hotbed_temp
865
+
866
+ @property
867
+ def curr_nozzle_temp(self) -> int:
868
+ return self._curr_nozzle_temp
869
+
870
+ @classmethod
871
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicMachineParameter | None:
872
+ if data is None:
873
+ return None
874
+
875
+ return cls(
876
+ curr_hotbed_temp=data['curr_hotbed_temp'],
877
+ curr_nozzle_temp=data['curr_nozzle_temp'],
878
+ )
879
+
880
+ def update_current_temps(self, new_hotbed_temp: int, new_nozzle_temp: int) -> None:
881
+ self._curr_hotbed_temp = int(new_hotbed_temp)
882
+ self._curr_nozzle_temp = int(new_nozzle_temp)
883
+
884
+ def __repr__(self) -> str:
885
+ return f"AnycubicMachineParameter(curr_hotbed_temp={self._curr_hotbed_temp}, curr_nozzle_temp={self._curr_nozzle_temp})"
886
+
887
+
888
+ class AnycubicMachineFirmwareInfo:
889
+ __slots__ = (
890
+ "_need_update",
891
+ "_firmware_version",
892
+ "_update_progress",
893
+ "_update_date",
894
+ "_update_status",
895
+ "_update_desc",
896
+ "_force_update",
897
+ "_target_version",
898
+ "_time_cost",
899
+ "_box_id",
900
+ "_download_progress",
901
+ "_is_downloading",
902
+ "_is_updating",
903
+ )
904
+
905
+ def __init__(
906
+ self,
907
+ need_update: int,
908
+ firmware_version: str,
909
+ update_progress: int | None = None,
910
+ update_date: int | None = None,
911
+ update_status: str | None = None,
912
+ update_desc: str | None = None,
913
+ force_update: str | None = None,
914
+ target_version: str | None = None,
915
+ time_cost: int | None = None,
916
+ box_id: int | None = None,
917
+ ) -> None:
918
+ self.set_need_update(need_update)
919
+ self.set_firmware_version(firmware_version)
920
+ self.set_update_progress(update_progress)
921
+ self.set_update_date(update_date)
922
+ self.set_update_status(update_status)
923
+ self.set_update_desc(update_desc)
924
+ self.set_force_update(force_update)
925
+ self.set_target_version(target_version)
926
+ self.set_time_cost(time_cost)
927
+ self.set_box_id(box_id)
928
+
929
+ self._download_progress: int = 0
930
+ self._is_downloading: bool = False
931
+ self._is_updating: bool = False
932
+
933
+ @property
934
+ def firmware_version(self) -> str:
935
+ return self._firmware_version
936
+
937
+ @property
938
+ def update_available(self) -> bool:
939
+ return self._need_update == 1
940
+
941
+ @property
942
+ def update_progress(self) -> int:
943
+ return self._update_progress
944
+
945
+ @property
946
+ def download_progress(self) -> int:
947
+ return self._download_progress
948
+
949
+ @property
950
+ def total_progress(self) -> int | float | bool:
951
+ if self._is_updating or self._is_downloading:
952
+ if self._update_progress == 0 and self._download_progress > 0:
953
+ return min(self._download_progress / 2, 100)
954
+ elif self._update_progress > 0:
955
+ return min(self._update_progress / 2 + 50, 100)
956
+ return 1
957
+ return False
958
+
959
+ @property
960
+ def available_version(self) -> str | None:
961
+ return self._target_version
962
+
963
+ @property
964
+ def is_updating(self) -> bool:
965
+ return self._is_updating
966
+
967
+ @property
968
+ def is_downloading(self) -> bool:
969
+ return self._is_downloading
970
+
971
+ @classmethod
972
+ def from_json(cls, data: dict[str, Any] | None) -> AnycubicMachineFirmwareInfo | None:
973
+ if data is None:
974
+ return None
975
+
976
+ return cls(
977
+ need_update=data['need_update'],
978
+ firmware_version=data['firmware_version'],
979
+ update_progress=data.get('update_progress'),
980
+ update_date=data.get('update_date'),
981
+ update_status=data.get('update_status'),
982
+ update_desc=data.get('update_desc'),
983
+ force_update=data.get('force_update'),
984
+ target_version=data.get('target_version'),
985
+ time_cost=data.get('time_cost'),
986
+ box_id=data.get('box_id'),
987
+ )
988
+
989
+ def update_from_json(self, data: dict[str, Any] | None) -> None:
990
+ if data is None:
991
+ return
992
+
993
+ self.set_need_update(data['need_update'])
994
+ self.set_firmware_version(data['firmware_version'])
995
+
996
+ if data.get('update_progress') is not None:
997
+ self.set_update_progress(data['update_progress'])
998
+
999
+ self.set_update_date(data.get('update_date'))
1000
+ self.set_update_status(data.get('update_status'))
1001
+ self.set_update_desc(data.get('update_desc'))
1002
+ self.set_force_update(data.get('force_update'))
1003
+ self.set_target_version(data.get('target_version'))
1004
+ self.set_time_cost(data.get('time_cost'))
1005
+ self.set_box_id(data.get('box_id'))
1006
+
1007
+ def update_version(self, new_version: str) -> None:
1008
+ if self._firmware_version != str(new_version):
1009
+ self.set_firmware_version(new_version)
1010
+
1011
+ if self._is_updating:
1012
+ self.set_is_updating(False)
1013
+
1014
+ if self._is_downloading:
1015
+ self.set_is_downloading(False)
1016
+
1017
+ self.set_download_progress(0)
1018
+ self.set_update_progress(0)
1019
+ self.set_need_update(0)
1020
+
1021
+ def set_need_update(self, need_update: int) -> None:
1022
+ self._need_update = int(need_update)
1023
+
1024
+ def set_firmware_version(self, firmware_version: str) -> None:
1025
+ self._firmware_version = str(firmware_version)
1026
+
1027
+ def set_update_date(self, update_date: int | None) -> None:
1028
+ self._update_date = int(update_date) if update_date is not None else None
1029
+
1030
+ def set_update_status(self, update_status: str | None) -> None:
1031
+ self._update_status = str(update_status) if update_status is not None else None
1032
+
1033
+ def set_update_desc(self, update_desc: str | None) -> None:
1034
+ self._update_desc = str(update_desc) if update_desc is not None else None
1035
+
1036
+ def set_force_update(self, force_update: str | None) -> None:
1037
+ self._force_update = str(force_update) if force_update is not None else None
1038
+
1039
+ def set_target_version(self, target_version: str | None) -> None:
1040
+ self._target_version = str(target_version) if target_version is not None else None
1041
+
1042
+ def set_time_cost(self, time_cost: int | None) -> None:
1043
+ self._time_cost = int(time_cost) if time_cost is not None else None
1044
+
1045
+ def set_box_id(self, box_id: int | None) -> None:
1046
+ self._box_id = int(box_id) if box_id is not None else None
1047
+
1048
+ def set_is_updating(self, is_updating: bool) -> None:
1049
+ self._is_updating = bool(is_updating)
1050
+
1051
+ def set_is_downloading(self, is_downloading: bool) -> None:
1052
+ self._is_downloading = bool(is_downloading)
1053
+
1054
+ def set_update_progress(self, update_progress: int | None) -> None:
1055
+ self._update_progress = int(update_progress) if update_progress is not None else 0
1056
+
1057
+ def set_download_progress(self, download_progress: int) -> None:
1058
+ self._download_progress = int(download_progress)
1059
+
1060
+ def __repr__(self) -> str:
1061
+ return f"AnycubicMachineFirmwareInfo(need_update={self._need_update}, firmware_version={self._firmware_version})"
1062
+
1063
+
1064
+ class AnycubicMachineColorInfo:
1065
+ __slots__ = (
1066
+ "_raw_color_list",
1067
+ "_color_list",
1068
+ )
1069
+
1070
+ def __init__(
1071
+ self,
1072
+ color_list: list[list[int]],
1073
+ ) -> None:
1074
+ self._raw_color_list: list[list[int]] = color_list
1075
+ self._color_list: list[list[int]] = list()
1076
+ self._set_color_list()
1077
+
1078
+ def _set_color_list(
1079
+ self,
1080
+ ) -> None:
1081
+ extended_colors_found = False
1082
+ if len(self._raw_color_list) > 4:
1083
+ for x in self._raw_color_list[4:]:
1084
+ if any([c != -2 for c in x]):
1085
+ extended_colors_found = True
1086
+
1087
+ self._color_list = (
1088
+ self._raw_color_list[:4]
1089
+ if not extended_colors_found else
1090
+ self._raw_color_list[:]
1091
+ )
1092
+
1093
+ @classmethod
1094
+ def from_json(cls, data: list[list[int]] | None) -> AnycubicMachineColorInfo | None:
1095
+ if data is None or not isinstance(data, list):
1096
+ return None
1097
+
1098
+ return cls(
1099
+ color_list=data,
1100
+ )
1101
+
1102
+ @property
1103
+ def color_list(self) -> list[list[int]]:
1104
+ return self._color_list
1105
+
1106
+ def __repr__(self) -> str:
1107
+ return f"AnycubicMachineColorInfo(color_list={self.color_list})"