flashforge-python-api 1.3.5__py3-none-any.whl → 1.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
flashforge/__init__.py CHANGED
@@ -128,7 +128,7 @@ from .tcp import (
128
128
  )
129
129
 
130
130
  FiveMClient = FlashForgeClient
131
- __version__ = "1.3.5"
131
+ __version__ = "1.4.0"
132
132
  __author__ = "FlashForge Python API Contributors"
133
133
  __email__ = "notghosttypes@gmail.com"
134
134
  __description__ = "Python library for controlling FlashForge 3D printers"
@@ -46,6 +46,19 @@ PID_MODEL_NAMES: dict[int, str] = {
46
46
  }
47
47
 
48
48
 
49
+ # The one state in which the firmware actually counts `estimatedTime` down.
50
+ # Outside it the field freezes at its last value while the wall clock keeps
51
+ # moving, so `now() + estimatedTime` walks forward one minute per minute instead
52
+ # of holding still - a paused print appears to recede forever. The duration
53
+ # stays correct throughout; only its conversion to an absolute timestamp is
54
+ # invalid, which is why `print_eta` is ungated and `completion_time` is not.
55
+ #
56
+ # HEATING is deliberately excluded. The pre-print warmup does not advance the
57
+ # job either, so the same drift applies - it just lasts minutes rather than
58
+ # hours, which is why it is easy to miss.
59
+ _ADVANCING_STATES = frozenset({MachineState.PRINTING})
60
+
61
+
49
62
  class MachineInfoParser:
50
63
  """
51
64
  Transforms printer detail data from the API response format into a structured FFMachineInfo object.
@@ -75,7 +88,14 @@ class MachineInfoParser:
75
88
  formatted_run_time = MachineInfoParser._format_time_from_seconds(
76
89
  getattr(detail, "print_duration", 0) or 0
77
90
  )
78
- completion_time = datetime.now() + timedelta(seconds=estimated_time)
91
+ machine_state = MachineInfoParser._get_machine_state(
92
+ getattr(detail, "status", "") or ""
93
+ )
94
+ completion_time = (
95
+ datetime.now() + timedelta(seconds=estimated_time)
96
+ if machine_state in _ADVANCING_STATES
97
+ else None
98
+ )
79
99
 
80
100
  total_minutes = getattr(detail, "cumulative_print_time", 0) or 0
81
101
  hours = total_minutes // 60
@@ -255,9 +275,7 @@ class MachineInfoParser:
255
275
  print_speed_adjust=getattr(detail, "print_speed_adjust", 0) or 0,
256
276
  filament_type=getattr(detail, "right_filament_type", "") or "",
257
277
  # Machine state
258
- machine_state=MachineInfoParser._get_machine_state(
259
- getattr(detail, "status", "") or ""
260
- ),
278
+ machine_state=machine_state,
261
279
  status=getattr(detail, "status", "") or "",
262
280
  total_print_layers=getattr(detail, "target_print_layer", 0) or 0,
263
281
  tvoc=getattr(detail, "tvoc", 0) or 0,
@@ -514,7 +514,12 @@ class FFMachineInfo(BaseModel):
514
514
 
515
515
  # Extras
516
516
  print_eta: str = "00:00"
517
- completion_time: datetime = Field(default_factory=datetime.now)
517
+ # None whenever the print is not advancing (paused, heating, ready, error,
518
+ # ...). The firmware freezes `estimatedTime` outside the PRINTING state, so
519
+ # an absolute timestamp derived from it would recede in real time rather
520
+ # than hold. Use `print_eta` / `estimated_time` for the remaining duration,
521
+ # which stays valid in every state.
522
+ completion_time: datetime | None = None
518
523
  formatted_run_time: str = "00:00"
519
524
  formatted_total_run_time: str = "0h:0m"
520
525
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flashforge-python-api
3
- Version: 1.3.5
3
+ Version: 1.4.0
4
4
  Summary: A comprehensive Python library for controlling FlashForge 3D printers
5
5
  Project-URL: Homepage, https://github.com/GhostTypes/ff-5mp-api-py
6
6
  Project-URL: Documentation, https://github.com/GhostTypes/ff-5mp-api-py#readme
@@ -1,4 +1,4 @@
1
- flashforge/__init__.py,sha256=rWsmx8X1akurtqwcS_cSeZGkzbSXc3Nnd1xeNsnAAj4,5472
1
+ flashforge/__init__.py,sha256=cYJmX39_FZxN6yyHkwepT_g9mnU2hHuVYuv3Lpg6seY,5472
2
2
  flashforge/client.py,sha256=nDtnv3y9XlEQknIkgIUiuOYAiyTEGbQ7tHBdCs2fg1I,21432
3
3
  flashforge/exceptions.py,sha256=rZwBJHyqqtoI6cgd8iGOvPH8EDcytA3lyU3FoVMJgyU,1732
4
4
  flashforge/api/__init__.py,sha256=vQz-DkG6LTH39bI4fyiUc0D9jQzemLh45pORLptSOlg,335
@@ -9,7 +9,7 @@ flashforge/api/controls/__init__.py,sha256=53s-H25Pjwr0kvPk8MZ2Twy8VHGqGcO6Q6uBp
9
9
  flashforge/api/controls/control.py,sha256=OgE7K6NkFLwFN1r_q5g1RPwYC8MCt0f6L5CZxDW44d8,15151
10
10
  flashforge/api/controls/creator5_palette.py,sha256=zdD3PIXx7hCVj2Fmv1CSFOaqogRUPeBaymgY2DFiMxk,8835
11
11
  flashforge/api/controls/files.py,sha256=Jk2ySrJdw2QDk1CJlGfY4bTmZJocx4GXztkEqE4rRaI,8830
12
- flashforge/api/controls/info.py,sha256=O6NVGSRwhArUqxCGXHK5WV20-Nn_8rHGUMbZheXXEjs,23973
12
+ flashforge/api/controls/info.py,sha256=7E2TtfFgT79m9lI3nBIvO-536dhl4xzwe1L9XCWVZ78,24836
13
13
  flashforge/api/controls/job_control.py,sha256=NnACm4LPUz4n8lnRiUl33jilWekS1b6HQTbP--nDzZc,33225
14
14
  flashforge/api/controls/temp_control.py,sha256=EOO5TkODirjFcnQ7rZrirxAweHBdVin032AWj-Z8VQs,13040
15
15
  flashforge/api/filament/__init__.py,sha256=isT2dl0hzUS0xMTXMm4Tip0GTG1gCsm8LKWa9xPu4Y8,104
@@ -24,7 +24,7 @@ flashforge/api/network/utils.py,sha256=Q5-Vj_1VN611QV_TGpDzrrZ2X8PqaGT0j00BhSHv5
24
24
  flashforge/discovery/__init__.py,sha256=G0WiP70EhfHdjXR1RNlv6xjhyHOdo-HWyOm9J0ds4SM,828
25
25
  flashforge/discovery/discovery.py,sha256=-hOmVIpn8gu-rPYo8FRBfhKb_tBqwamLfmoPVYaDzLI,27614
26
26
  flashforge/models/__init__.py,sha256=hdcK0E4KeDfv_A8Y2aPOHgHziwTjP1RPb_VP-89dOzQ,1086
27
- flashforge/models/machine_info.py,sha256=o0rpT6DPWojg8VMfYleMFIqEaidDvsY6E0MstaVHOT0,24065
27
+ flashforge/models/machine_info.py,sha256=OvvpjjUtmOHyogYADFfRJRQnwwPQnjiGVCkXRNdka7Y,24397
28
28
  flashforge/models/responses.py,sha256=10-8yFfZtLuDmH1TK2xVYl-Uf-zT2WEJnpb2H5ZK3ZU,10637
29
29
  flashforge/tcp/__init__.py,sha256=hpnqoWHeRtTwJPzdsVlwGt1njKbAkrgIHKADkLSIRec,1317
30
30
  flashforge/tcp/a3_client.py,sha256=Aqb6MuKkjnNUVdE2LbZKd7bPlFK8XPIm17C_BG_PuNU,15867
@@ -42,8 +42,8 @@ flashforge/tcp/parsers/print_status.py,sha256=C-KzukhK0TR86AP3t3XrMH4dief6pa3I-y
42
42
  flashforge/tcp/parsers/printer_info.py,sha256=CHPs6nJfEByXyG3co7Nb8_ygggxkYuc7A9O9bpQEqXE,5441
43
43
  flashforge/tcp/parsers/temp_info.py,sha256=9wRGUM9cKvDiZD3SIxBx_qVLZbeXoYsoY3-R3vN3H4g,7938
44
44
  flashforge/tcp/parsers/thumbnail_info.py,sha256=1U1S_gcIZ2lDpEA4622ywUew6TVw0BnzjlBAiihQwzk,10478
45
- flashforge_python_api-1.3.5.dist-info/METADATA,sha256=oSmQO3OQPkDynC5evAjLOdK6jpCaD2SmT7DZk6lC5CY,4970
46
- flashforge_python_api-1.3.5.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
47
- flashforge_python_api-1.3.5.dist-info/entry_points.txt,sha256=AkOxlsLvQ7cvMLxn7tlzfKp_DCH2hXhbVceHIXxawpU,66
48
- flashforge_python_api-1.3.5.dist-info/licenses/LICENSE,sha256=-cTA-hrmvlb3pqlQrBZQXUnKayhUjsLJMPb7TD91frM,1067
49
- flashforge_python_api-1.3.5.dist-info/RECORD,,
45
+ flashforge_python_api-1.4.0.dist-info/METADATA,sha256=VQsv_msrpBzurF7zMQUadt7jpyy1ljomJQxV_XhALIg,4970
46
+ flashforge_python_api-1.4.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
47
+ flashforge_python_api-1.4.0.dist-info/entry_points.txt,sha256=AkOxlsLvQ7cvMLxn7tlzfKp_DCH2hXhbVceHIXxawpU,66
48
+ flashforge_python_api-1.4.0.dist-info/licenses/LICENSE,sha256=-cTA-hrmvlb3pqlQrBZQXUnKayhUjsLJMPb7TD91frM,1067
49
+ flashforge_python_api-1.4.0.dist-info/RECORD,,