anycubic-cloud-api 0.3.2__tar.gz → 0.4.0__tar.gz
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.
- {anycubic_cloud_api-0.3.2/src/anycubic_cloud_api.egg-info → anycubic_cloud_api-0.4.0}/PKG-INFO +1 -1
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/pyproject.toml +1 -1
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/printer.py +50 -14
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0/src/anycubic_cloud_api.egg-info}/PKG-INFO +1 -1
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/tests/test_lan_reports.py +119 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/LICENSE +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/README.md +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/setup.cfg +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/__init__.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/anycubic_api.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/api/base.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/api/functions.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/api/mqtt.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/const/api_endpoints.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/const/const.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/const/enums.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/const/lan.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/const/mqtt.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/consumable.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/files.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/gcode_file.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/orders.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/print_response.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/print_speed_mode.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/printer_properties.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/printing_settings.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/project.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/exceptions/error_strings.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/exceptions/exceptions.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/helpers/helpers.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/lan/__init__.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/lan/client.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/lan/handshake.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/models/auth.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/models/cloud_upload.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/models/http.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/resources/anycubic_mqqt_tls_ca.crt +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/resources/anycubic_mqqt_tls_client.crt +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/resources/anycubic_mqqt_tls_client.key +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/SOURCES.txt +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/dependency_links.txt +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/requires.txt +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/top_level.txt +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/tests/test_axis_position.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/tests/test_lan_client.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/tests/test_lan_handshake.py +0 -0
- {anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/tests/test_partial_reports.py +0 -0
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/printer.py
RENAMED
|
@@ -274,6 +274,22 @@ class AnycubicPrinter:
|
|
|
274
274
|
else:
|
|
275
275
|
self._type_function_ids = list()
|
|
276
276
|
|
|
277
|
+
def set_material_type_from_device_type(self, device_type: str | None) -> None:
|
|
278
|
+
"""Infer what the printer prints from what kind of machine it says it is.
|
|
279
|
+
|
|
280
|
+
The cloud states this outright. A printer reached over its own network
|
|
281
|
+
does not, but its discovery document names a device type -- and `fdm`
|
|
282
|
+
means filament as surely as the cloud saying so. Without it every
|
|
283
|
+
filament entity is filtered out as belonging to a different machine.
|
|
284
|
+
"""
|
|
285
|
+
if self._material_type is not None or not device_type:
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
if str(device_type).lower() == "fdm":
|
|
289
|
+
self._set_material_type("filament")
|
|
290
|
+
elif str(device_type).lower() in ("lcd", "dlp", "resin"):
|
|
291
|
+
self._set_material_type("resin")
|
|
292
|
+
|
|
277
293
|
def _set_material_type(self, material_type: str | None) -> None:
|
|
278
294
|
self._material_type: AnycubicPrinterMaterialType | str | None = None
|
|
279
295
|
|
|
@@ -375,6 +391,26 @@ class AnycubicPrinter:
|
|
|
375
391
|
if not self._ignore_init_errors:
|
|
376
392
|
raise e
|
|
377
393
|
|
|
394
|
+
def _apply_current_temps(self, hotbed: Any, nozzle: Any) -> None:
|
|
395
|
+
"""Record the live temperatures, creating the holder if need be.
|
|
396
|
+
|
|
397
|
+
The cloud builds this object when the printer is first fetched. With
|
|
398
|
+
only a local connection there is no such fetch, so it has to be made
|
|
399
|
+
from the first report that carries temperatures -- otherwise every
|
|
400
|
+
temperature entity reads unavailable on a working printer.
|
|
401
|
+
"""
|
|
402
|
+
if hotbed is None or nozzle is None:
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
if self._parameter is None:
|
|
406
|
+
self._set_parameter({
|
|
407
|
+
'curr_hotbed_temp': hotbed,
|
|
408
|
+
'curr_nozzle_temp': nozzle,
|
|
409
|
+
})
|
|
410
|
+
return
|
|
411
|
+
|
|
412
|
+
self._parameter.update_current_temps(hotbed, nozzle)
|
|
413
|
+
|
|
378
414
|
def _set_parameter(
|
|
379
415
|
self,
|
|
380
416
|
parameter: dict[str, Any] | None,
|
|
@@ -893,8 +929,7 @@ class AnycubicPrinter:
|
|
|
893
929
|
self._chamber_temp = data.get('curr_chamber_temp')
|
|
894
930
|
self._target_chamber_temp = data.get('target_chamber_temp')
|
|
895
931
|
|
|
896
|
-
|
|
897
|
-
self.parameter.update_current_temps(curr_hotbed, curr_nozzle)
|
|
932
|
+
self._apply_current_temps(curr_hotbed, curr_nozzle)
|
|
898
933
|
|
|
899
934
|
if self._latest_project:
|
|
900
935
|
self._latest_project.update_target_temps(target_hotbed, target_nozzle)
|
|
@@ -1021,12 +1056,8 @@ class AnycubicPrinter:
|
|
|
1021
1056
|
# each is applied only if it is actually there.
|
|
1022
1057
|
settings = data.get('settings') or {}
|
|
1023
1058
|
|
|
1024
|
-
if
|
|
1025
|
-
self.
|
|
1026
|
-
and 'curr_hotbed_temp' in data
|
|
1027
|
-
and 'curr_nozzle_temp' in data
|
|
1028
|
-
):
|
|
1029
|
-
self.parameter.update_current_temps(
|
|
1059
|
+
if 'curr_hotbed_temp' in data and 'curr_nozzle_temp' in data:
|
|
1060
|
+
self._apply_current_temps(
|
|
1030
1061
|
data['curr_hotbed_temp'],
|
|
1031
1062
|
data['curr_nozzle_temp'],
|
|
1032
1063
|
)
|
|
@@ -1257,11 +1288,10 @@ class AnycubicPrinter:
|
|
|
1257
1288
|
temp = data.get('temp')
|
|
1258
1289
|
|
|
1259
1290
|
if temp:
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
)
|
|
1291
|
+
self._apply_current_temps(
|
|
1292
|
+
temp.get('curr_hotbed_temp'),
|
|
1293
|
+
temp.get('curr_nozzle_temp'),
|
|
1294
|
+
)
|
|
1265
1295
|
# A Kobra S1 reports chamber temperatures of zero because it has no
|
|
1266
1296
|
# chamber sensor, so they are kept raw rather than turned into an
|
|
1267
1297
|
# always-zero entity.
|
|
@@ -1693,7 +1723,13 @@ class AnycubicPrinter:
|
|
|
1693
1723
|
|
|
1694
1724
|
@property
|
|
1695
1725
|
def supports_function_multi_color_box(self) -> bool:
|
|
1696
|
-
|
|
1726
|
+
if AnycubicFunctionID.MULTI_COLOR_BOX in self._type_function_ids:
|
|
1727
|
+
return True
|
|
1728
|
+
|
|
1729
|
+
# The function list comes from the cloud, and a printer reached only
|
|
1730
|
+
# over its own network has none. One that is reporting a box plainly
|
|
1731
|
+
# supports one, whatever any list says.
|
|
1732
|
+
return self.connected_ace_units > 0
|
|
1697
1733
|
|
|
1698
1734
|
@property
|
|
1699
1735
|
def supports_function_ai_detection(self) -> bool:
|
|
@@ -296,3 +296,122 @@ class TestAvailabilityFromLocalReports:
|
|
|
296
296
|
apply(printer, report)
|
|
297
297
|
|
|
298
298
|
assert printer.printer_online is True
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class TestTemperaturesWithoutTheCloud:
|
|
302
|
+
"""The cloud builds the temperature holder; a local-only printer has none."""
|
|
303
|
+
|
|
304
|
+
def test_an_info_report_creates_it(self):
|
|
305
|
+
printer = make_printer()
|
|
306
|
+
|
|
307
|
+
apply(printer, INFO_REPORT)
|
|
308
|
+
|
|
309
|
+
assert printer.parameter is not None
|
|
310
|
+
assert printer.curr_nozzle_temp == 34
|
|
311
|
+
assert printer.curr_hotbed_temp == 31
|
|
312
|
+
|
|
313
|
+
def test_a_temperature_report_creates_it(self):
|
|
314
|
+
printer = make_printer()
|
|
315
|
+
|
|
316
|
+
apply(printer, TestQueryActionReplies.TEMPERATURE)
|
|
317
|
+
|
|
318
|
+
assert printer.curr_nozzle_temp == 34
|
|
319
|
+
|
|
320
|
+
def test_later_reports_update_it(self):
|
|
321
|
+
printer = make_printer()
|
|
322
|
+
apply(printer, INFO_REPORT)
|
|
323
|
+
|
|
324
|
+
hotter = {**INFO_REPORT, "data": {**INFO_REPORT["data"]}}
|
|
325
|
+
hotter["data"]["temp"] = {**hotter["data"]["temp"], "curr_nozzle_temp": 210}
|
|
326
|
+
apply(printer, hotter)
|
|
327
|
+
|
|
328
|
+
assert printer.curr_nozzle_temp == 210
|
|
329
|
+
|
|
330
|
+
def test_a_report_without_temperatures_leaves_it_alone(self):
|
|
331
|
+
printer = make_printer()
|
|
332
|
+
report = {**INFO_REPORT, "data": {**INFO_REPORT["data"]}}
|
|
333
|
+
del report["data"]["temp"]
|
|
334
|
+
|
|
335
|
+
apply(printer, report)
|
|
336
|
+
|
|
337
|
+
assert printer.parameter is None
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class TestWhatTheCloudWouldHaveSaid:
|
|
341
|
+
"""Two facts only the cloud states, which entity filtering depends on.
|
|
342
|
+
|
|
343
|
+
Without them every filament entity is filtered out as belonging to a
|
|
344
|
+
different kind of machine, and every ACE entity as unsupported -- so a
|
|
345
|
+
printer reached locally ends up with almost no entities at all.
|
|
346
|
+
"""
|
|
347
|
+
|
|
348
|
+
def test_an_fdm_device_type_means_filament(self):
|
|
349
|
+
printer = make_printer()
|
|
350
|
+
|
|
351
|
+
printer.set_material_type_from_device_type("fdm")
|
|
352
|
+
|
|
353
|
+
assert str(printer.material_type) == "Filament"
|
|
354
|
+
|
|
355
|
+
@pytest.mark.parametrize("device_type", ["lcd", "dlp", "resin", "LCD"])
|
|
356
|
+
def test_a_resin_device_type_means_resin(self, device_type):
|
|
357
|
+
printer = make_printer()
|
|
358
|
+
|
|
359
|
+
printer.set_material_type_from_device_type(device_type)
|
|
360
|
+
|
|
361
|
+
assert str(printer.material_type) == "Resin"
|
|
362
|
+
|
|
363
|
+
@pytest.mark.parametrize("device_type", [None, "", "something-new"])
|
|
364
|
+
def test_an_unknown_device_type_leaves_it_unset(self, device_type):
|
|
365
|
+
"""Better unset than wrong -- a wrong guess hides the right entities."""
|
|
366
|
+
printer = make_printer()
|
|
367
|
+
|
|
368
|
+
printer.set_material_type_from_device_type(device_type)
|
|
369
|
+
|
|
370
|
+
assert printer.material_type is None
|
|
371
|
+
|
|
372
|
+
def test_the_cloud_wins_when_it_has_already_spoken(self):
|
|
373
|
+
printer = AnycubicPrinter(
|
|
374
|
+
api_parent=MagicMock(),
|
|
375
|
+
machine_type=20025,
|
|
376
|
+
machine_name="x",
|
|
377
|
+
id=1,
|
|
378
|
+
material_type="resin",
|
|
379
|
+
ignore_init_errors=True,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
printer.set_material_type_from_device_type("fdm")
|
|
383
|
+
|
|
384
|
+
assert str(printer.material_type) == "Resin"
|
|
385
|
+
|
|
386
|
+
def test_a_reported_box_means_the_printer_supports_one(self):
|
|
387
|
+
"""The cloud's function list is absent on a local connection."""
|
|
388
|
+
printer = AnycubicPrinter(
|
|
389
|
+
api_parent=MagicMock(),
|
|
390
|
+
machine_type=20025,
|
|
391
|
+
machine_name="x",
|
|
392
|
+
id=1,
|
|
393
|
+
multi_color_box=[{"id": 0, "box_id": 0, "slots": []}],
|
|
394
|
+
ignore_init_errors=True,
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
assert printer.connected_ace_units == 1
|
|
398
|
+
assert printer.supports_function_multi_color_box is True
|
|
399
|
+
|
|
400
|
+
def test_no_box_means_no_support(self):
|
|
401
|
+
printer = make_printer()
|
|
402
|
+
|
|
403
|
+
assert printer.connected_ace_units == 0
|
|
404
|
+
assert printer.supports_function_multi_color_box is False
|
|
405
|
+
|
|
406
|
+
def test_the_cloud_function_list_still_counts_with_no_box_attached(self):
|
|
407
|
+
"""A supported-but-detached ACE must not read as unsupported."""
|
|
408
|
+
printer = AnycubicPrinter(
|
|
409
|
+
api_parent=MagicMock(),
|
|
410
|
+
machine_type=20025,
|
|
411
|
+
machine_name="x",
|
|
412
|
+
id=1,
|
|
413
|
+
type_function_ids=[2006],
|
|
414
|
+
ignore_init_errors=True,
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
assert printer.supports_function_multi_color_box is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/anycubic_api.py
RENAMED
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/api/functions.py
RENAMED
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/const/api_endpoints.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/files.py
RENAMED
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/orders.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/data_models/project.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/helpers/helpers.py
RENAMED
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/lan/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/lan/handshake.py
RENAMED
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api/models/cloud_upload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/requires.txt
RENAMED
|
File without changes
|
{anycubic_cloud_api-0.3.2 → anycubic_cloud_api-0.4.0}/src/anycubic_cloud_api.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|