flashforge-python-api 1.0.1__py3-none-any.whl → 1.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 (42) hide show
  1. flashforge/__init__.py +62 -29
  2. flashforge/api/__init__.py +1 -0
  3. flashforge/api/constants/__init__.py +1 -0
  4. flashforge/api/constants/commands.py +1 -0
  5. flashforge/api/constants/endpoints.py +1 -0
  6. flashforge/api/controls/__init__.py +1 -0
  7. flashforge/api/controls/control.py +64 -61
  8. flashforge/api/controls/files.py +28 -26
  9. flashforge/api/controls/info.py +84 -85
  10. flashforge/api/controls/job_control.py +120 -82
  11. flashforge/api/controls/temp_control.py +14 -11
  12. flashforge/api/misc/__init__.py +1 -1
  13. flashforge/api/network/__init__.py +2 -1
  14. flashforge/api/network/utils.py +7 -8
  15. flashforge/client.py +131 -63
  16. flashforge/discovery/__init__.py +30 -3
  17. flashforge/discovery/discovery.py +637 -308
  18. flashforge/models/__init__.py +11 -10
  19. flashforge/models/machine_info.py +220 -100
  20. flashforge/models/responses.py +103 -43
  21. flashforge/tcp/__init__.py +25 -17
  22. flashforge/tcp/a3_client.py +405 -0
  23. flashforge/tcp/ff_client.py +93 -90
  24. flashforge/tcp/gcode/__init__.py +4 -2
  25. flashforge/tcp/gcode/a3_gcode_controller.py +109 -0
  26. flashforge/tcp/gcode/gcode_controller.py +48 -36
  27. flashforge/tcp/gcode/gcodes.py +7 -1
  28. flashforge/tcp/parsers/__init__.py +11 -11
  29. flashforge/tcp/parsers/endstop_status.py +103 -132
  30. flashforge/tcp/parsers/location_info.py +26 -13
  31. flashforge/tcp/parsers/print_status.py +49 -56
  32. flashforge/tcp/parsers/printer_info.py +38 -48
  33. flashforge/tcp/parsers/temp_info.py +46 -47
  34. flashforge/tcp/parsers/thumbnail_info.py +65 -40
  35. flashforge/tcp/tcp_client.py +296 -293
  36. flashforge_python_api-1.1.0.dist-info/METADATA +305 -0
  37. flashforge_python_api-1.1.0.dist-info/RECORD +45 -0
  38. {flashforge_python_api-1.0.1.dist-info → flashforge_python_api-1.1.0.dist-info}/WHEEL +1 -1
  39. {flashforge_python_api-1.0.1.dist-info → flashforge_python_api-1.1.0.dist-info}/licenses/LICENSE +21 -21
  40. flashforge_python_api-1.0.1.dist-info/METADATA +0 -211
  41. flashforge_python_api-1.0.1.dist-info/RECORD +0 -43
  42. {flashforge_python_api-1.0.1.dist-info → flashforge_python_api-1.1.0.dist-info}/entry_points.txt +0 -0
flashforge/__init__.py CHANGED
@@ -7,28 +7,28 @@ temperature control, and real-time communication.
7
7
 
8
8
  Example:
9
9
  Basic usage example:
10
-
10
+
11
11
  ```python
12
12
  import asyncio
13
13
  from flashforge import FlashForgeClient
14
-
14
+
15
15
  async def main():
16
16
  async with FlashForgeClient("192.168.1.100", "serial123", "check456") as client:
17
17
  if await client.initialize():
18
18
  print(f"Connected to {client.printer_name}")
19
-
19
+
20
20
  # Get printer status
21
21
  status = await client.get_printer_status()
22
22
  print(f"Status: {status.machine_state}")
23
-
23
+
24
24
  # Control operations
25
25
  await client.control.set_led_on()
26
26
  await client.control.home_axes()
27
-
27
+
28
28
  # Temperature monitoring
29
29
  temps = await client.get_temperatures()
30
30
  print(f"Extruder: {temps.extruder_temp}°C")
31
-
31
+
32
32
  asyncio.run(main())
33
33
  ```
34
34
  """
@@ -44,47 +44,66 @@ from .api.controls import (
44
44
  JobControl,
45
45
  TempControl,
46
46
  )
47
+ from .api.filament import Filament
48
+ from .api.misc import Temperature as TempWrapper
49
+ from .api.misc import format_scientific_notation
50
+ from .api.network.fnet_code import FNetCode
47
51
 
48
52
  # Import utility classes
49
53
  from .api.network.utils import NetworkUtils
50
- from .api.network.fnet_code import FNetCode
51
- from .api.filament import Filament
52
- from .api.misc import Temperature as TempWrapper, format_scientific_notation
53
- from .client import FlashForgeClient
54
+ from .client import FiveMClientConnectionOptions, FlashForgeClient
54
55
 
55
56
  # Import discovery classes
56
57
  from .discovery import (
58
+ DiscoveredPrinter,
59
+ DiscoveryError,
60
+ DiscoveryMonitor,
61
+ DiscoveryOptions,
62
+ DiscoveryProtocol,
63
+ DiscoveryTimeoutError,
57
64
  FlashForgePrinter,
58
65
  FlashForgePrinterDiscovery,
66
+ InvalidResponseError,
67
+ PrinterDiscovery,
68
+ PrinterModel,
69
+ PrinterStatus,
70
+ SocketCreationError,
59
71
  )
60
72
 
61
73
  # Import key models for convenience
62
74
  from .models import (
75
+ AD5XLocalJobParams,
76
+ AD5XMaterialMapping,
77
+ AD5XSingleColorJobParams,
78
+ AD5XUploadParams,
63
79
  DetailResponse,
64
- FFMachineInfo,
65
- FFPrinterDetail,
66
80
  FFGcodeFileEntry,
67
81
  FFGcodeToolData,
82
+ FFMachineInfo,
83
+ FFPrinterDetail,
68
84
  FilamentArgs,
85
+ GCodeListResponse,
69
86
  GenericResponse,
87
+ IndepMatlInfo,
70
88
  MachineState,
89
+ MatlStationInfo,
71
90
  Product,
72
91
  ProductResponse,
73
- Temperature,
74
92
  SlotInfo,
75
- MatlStationInfo,
76
- IndepMatlInfo,
77
- AD5XMaterialMapping,
78
- AD5XLocalJobParams,
79
- AD5XSingleColorJobParams,
80
- AD5XUploadParams,
81
- GCodeListResponse,
93
+ Temperature,
82
94
  ThumbnailResponse,
83
95
  )
84
96
  from .tcp import (
97
+ A3BuildVolume,
98
+ A3FileEntry,
99
+ A3GCodeController,
100
+ A3PrinterInfo,
101
+ A3Thumbnail,
85
102
  Endstop,
86
103
  EndstopStatus,
104
+ FlashForgeA3Client,
87
105
  FlashForgeTcpClient,
106
+ FlashForgeTcpClientOptions,
88
107
  GCodeController,
89
108
  GCodes,
90
109
  LocationInfo,
@@ -103,7 +122,8 @@ from .tcp import (
103
122
  FlashForgeTcpClient as TcpClient,
104
123
  )
105
124
 
106
- __version__ = "1.0.0"
125
+ FiveMClient = FlashForgeClient
126
+ __version__ = "1.1.0"
107
127
  __author__ = "FlashForge Python API Contributors"
108
128
  __email__ = "notghosttypes@gmail.com"
109
129
  __description__ = "Python library for controlling FlashForge 3D printers"
@@ -112,7 +132,8 @@ __description__ = "Python library for controlling FlashForge 3D printers"
112
132
  __all__ = [
113
133
  # Main client class
114
134
  "FlashForgeClient",
115
-
135
+ "FiveMClient",
136
+ "FiveMClientConnectionOptions",
116
137
  # Data models
117
138
  "FFMachineInfo",
118
139
  "FFPrinterDetail",
@@ -125,7 +146,6 @@ __all__ = [
125
146
  "ProductResponse",
126
147
  "Product",
127
148
  "FilamentArgs",
128
-
129
149
  # AD5X models
130
150
  "SlotInfo",
131
151
  "MatlStationInfo",
@@ -136,17 +156,17 @@ __all__ = [
136
156
  "AD5XUploadParams",
137
157
  "GCodeListResponse",
138
158
  "ThumbnailResponse",
139
-
140
159
  # Control classes for advanced usage
141
160
  "Control",
142
161
  "JobControl",
143
162
  "Info",
144
163
  "Files",
145
164
  "TempControl",
146
-
147
165
  # TCP classes for low-level operations
148
166
  "TcpClient",
149
167
  "FlashForgeTcpClient",
168
+ "FlashForgeTcpClientOptions",
169
+ "FlashForgeA3Client",
150
170
  "PrinterInfo",
151
171
  "TempInfo",
152
172
  "TempData",
@@ -160,11 +180,25 @@ __all__ = [
160
180
  "ThumbnailInfo",
161
181
  "GCodes",
162
182
  "GCodeController",
163
-
183
+ "A3GCodeController",
184
+ "A3BuildVolume",
185
+ "A3PrinterInfo",
186
+ "A3FileEntry",
187
+ "A3Thumbnail",
164
188
  # Discovery classes
189
+ "PrinterDiscovery",
190
+ "DiscoveredPrinter",
191
+ "DiscoveryOptions",
192
+ "PrinterModel",
193
+ "DiscoveryProtocol",
194
+ "PrinterStatus",
195
+ "DiscoveryMonitor",
196
+ "DiscoveryError",
197
+ "InvalidResponseError",
198
+ "SocketCreationError",
199
+ "DiscoveryTimeoutError",
165
200
  "FlashForgePrinter",
166
201
  "FlashForgePrinterDiscovery",
167
-
168
202
  # Utilities
169
203
  "NetworkUtils",
170
204
  "FNetCode",
@@ -173,7 +207,6 @@ __all__ = [
173
207
  "format_scientific_notation",
174
208
  "Endpoints",
175
209
  "Commands",
176
-
177
210
  # Package metadata
178
211
  "__version__",
179
212
  "__author__",
@@ -182,7 +215,7 @@ __all__ = [
182
215
  ]
183
216
 
184
217
  # Convenience imports for common patterns
185
- from .models.machine_info import MachineState as State
218
+ State = MachineState
186
219
 
187
220
  # Add version info accessible as flashforge.version
188
221
  version = __version__
@@ -1,6 +1,7 @@
1
1
  """
2
2
  FlashForge Python API - API Package
3
3
  """
4
+
4
5
  from .constants import Commands, Endpoints
5
6
  from .controls import Control, Files, Info, JobControl, TempControl
6
7
  from .network import NetworkUtils
@@ -1,6 +1,7 @@
1
1
  """
2
2
  FlashForge Python API - Constants Package
3
3
  """
4
+
4
5
  from .commands import Commands
5
6
  from .endpoints import Endpoints
6
7
 
@@ -2,6 +2,7 @@ class Commands:
2
2
  """
3
3
  Commands used in the "new" HTTP API
4
4
  """
5
+
5
6
  LIGHT_CONTROL_CMD = "lightControl_cmd"
6
7
  PRINTER_CONTROL_CMD = "printerCtl_cmd"
7
8
  JOB_CONTROL_CMD = "jobCtl_cmd"
@@ -2,6 +2,7 @@ class Endpoints:
2
2
  """
3
3
  Endpoints for the "new" HTTP API
4
4
  """
5
+
5
6
  CONTROL = "/control"
6
7
  DETAIL = "/detail"
7
8
  GCODE_LIST = "/gcodeList"
@@ -1,6 +1,7 @@
1
1
  """
2
2
  FlashForge Python API - Controls Package
3
3
  """
4
+
4
5
  from .control import Control
5
6
  from .files import Files
6
7
  from .info import Info
@@ -1,7 +1,8 @@
1
1
  """
2
2
  FlashForge Python API - Control Module
3
3
  """
4
- from typing import TYPE_CHECKING, Any, Dict, Optional
4
+
5
+ from typing import TYPE_CHECKING, Any
5
6
 
6
7
  import aiohttp
7
8
 
@@ -25,12 +26,12 @@ class Control:
25
26
  def __init__(self, client: "FlashForgeClient"):
26
27
  """
27
28
  Creates an instance of the Control class.
28
-
29
+
29
30
  Args:
30
31
  client: The FlashForgeClient instance used for communication with the printer.
31
32
  """
32
33
  self.client = client
33
- self._tcp_client: Optional[TcpClient] = None
34
+ self._tcp_client: TcpClient | None = None
34
35
 
35
36
  @property
36
37
  def tcp_client(self) -> "TcpClient":
@@ -42,7 +43,7 @@ class Control:
42
43
  async def home_axes(self) -> bool:
43
44
  """
44
45
  Homes the X, Y, and Z axes of the printer.
45
-
46
+
46
47
  Returns:
47
48
  True if the command is successful, False otherwise.
48
49
  """
@@ -51,7 +52,7 @@ class Control:
51
52
  async def home_axes_rapid(self) -> bool:
52
53
  """
53
54
  Performs a rapid homing of the X, Y, and Z axes.
54
-
55
+
55
56
  Returns:
56
57
  True if the command is successful, False otherwise.
57
58
  """
@@ -61,12 +62,14 @@ class Control:
61
62
  """
62
63
  Turns on the external filtration system.
63
64
  Requires the printer to have filtration control.
64
-
65
+
65
66
  Returns:
66
67
  True if the command is successful, False otherwise.
67
68
  """
68
69
  if self.client.filtration_control:
69
- return await self._send_filtration_command(FilamentArgs(False, True))
70
+ return await self._send_filtration_command(
71
+ FilamentArgs(internal="close", external="open")
72
+ )
70
73
  print("SetExternalFiltrationOn() error, filtration not equipped.")
71
74
  return False
72
75
 
@@ -74,12 +77,14 @@ class Control:
74
77
  """
75
78
  Turns on the internal filtration system.
76
79
  Requires the printer to have filtration control.
77
-
80
+
78
81
  Returns:
79
82
  True if the command is successful, False otherwise.
80
83
  """
81
84
  if self.client.filtration_control:
82
- return await self._send_filtration_command(FilamentArgs(True, False))
85
+ return await self._send_filtration_command(
86
+ FilamentArgs(internal="open", external="close")
87
+ )
83
88
  print("SetInternalFiltrationOn() error, filtration not equipped.")
84
89
  return False
85
90
 
@@ -87,12 +92,14 @@ class Control:
87
92
  """
88
93
  Turns off both internal and external filtration systems.
89
94
  Requires the printer to have filtration control.
90
-
95
+
91
96
  Returns:
92
97
  True if the command is successful, False otherwise.
93
98
  """
94
99
  if self.client.filtration_control:
95
- return await self._send_filtration_command(FilamentArgs(False, False))
100
+ return await self._send_filtration_command(
101
+ FilamentArgs(internal="close", external="close")
102
+ )
96
103
  print("SetFiltrationOff() error, filtration not equipped.")
97
104
  return False
98
105
 
@@ -100,7 +107,7 @@ class Control:
100
107
  """
101
108
  Turns on the printer's camera.
102
109
  Only applicable for Pro models.
103
-
110
+
104
111
  Returns:
105
112
  True if the command is successful, False otherwise.
106
113
  """
@@ -112,7 +119,7 @@ class Control:
112
119
  """
113
120
  Turns off the printer's camera.
114
121
  Only applicable for Pro models.
115
-
122
+
116
123
  Returns:
117
124
  True if the command is successful, False otherwise.
118
125
  """
@@ -123,10 +130,10 @@ class Control:
123
130
  async def set_speed_override(self, speed: int) -> bool:
124
131
  """
125
132
  Sets the print speed override.
126
-
133
+
127
134
  Args:
128
135
  speed: The desired print speed percentage (e.g., 100 for normal speed).
129
-
136
+
130
137
  Returns:
131
138
  True if the command is successful, False otherwise.
132
139
  """
@@ -135,10 +142,10 @@ class Control:
135
142
  async def set_z_axis_override(self, offset: float) -> bool:
136
143
  """
137
144
  Sets the Z-axis offset override.
138
-
145
+
139
146
  Args:
140
147
  offset: The Z-axis offset value.
141
-
148
+
142
149
  Returns:
143
150
  True if the command is successful, False otherwise.
144
151
  """
@@ -147,10 +154,10 @@ class Control:
147
154
  async def set_chamber_fan_speed(self, speed: int) -> bool:
148
155
  """
149
156
  Sets the chamber fan speed.
150
-
157
+
151
158
  Args:
152
159
  speed: The desired chamber fan speed percentage.
153
-
160
+
154
161
  Returns:
155
162
  True if the command is successful, False otherwise.
156
163
  """
@@ -159,10 +166,10 @@ class Control:
159
166
  async def set_cooling_fan_speed(self, speed: int) -> bool:
160
167
  """
161
168
  Sets the cooling fan speed.
162
-
169
+
163
170
  Args:
164
171
  speed: The desired cooling fan speed percentage.
165
-
172
+
166
173
  Returns:
167
174
  True if the command is successful, False otherwise.
168
175
  """
@@ -171,33 +178,31 @@ class Control:
171
178
  async def set_led_on(self) -> bool:
172
179
  """
173
180
  Turns on the printer's LED lights.
174
- Requires the printer to have LED control.
175
-
181
+
176
182
  Returns:
177
183
  True if the command is successful, False otherwise.
178
184
  """
179
- if self.client.led_control:
180
- return await self.send_control_command(Commands.LIGHT_CONTROL_CMD, {"status": "open"})
181
- print("SetLedOn() error, LEDs not equipped.")
182
- return False
185
+ if not self.client.led_control:
186
+ print("SetLedOn() error, LED control not equipped.")
187
+ return False
188
+ return await self.send_control_command(Commands.LIGHT_CONTROL_CMD, {"status": "open"})
183
189
 
184
190
  async def set_led_off(self) -> bool:
185
191
  """
186
192
  Turns off the printer's LED lights.
187
- Requires the printer to have LED control.
188
-
193
+
189
194
  Returns:
190
195
  True if the command is successful, False otherwise.
191
196
  """
192
- if self.client.led_control:
193
- return await self.send_control_command(Commands.LIGHT_CONTROL_CMD, {"status": "close"})
194
- print("SetLedOff() error, LEDs not equipped.")
195
- return False
197
+ if not self.client.led_control:
198
+ print("SetLedOff() error, LED control not equipped.")
199
+ return False
200
+ return await self.send_control_command(Commands.LIGHT_CONTROL_CMD, {"status": "close"})
196
201
 
197
202
  async def turn_runout_sensor_on(self) -> bool:
198
203
  """
199
204
  Turns on the filament runout sensor.
200
-
205
+
201
206
  Returns:
202
207
  True if the command is successful, False otherwise.
203
208
  """
@@ -206,30 +211,27 @@ class Control:
206
211
  async def turn_runout_sensor_off(self) -> bool:
207
212
  """
208
213
  Turns off the filament runout sensor.
209
-
214
+
210
215
  Returns:
211
216
  True if the command is successful, False otherwise.
212
217
  """
213
218
  return await self.tcp_client.turn_runout_sensor_off()
214
219
 
215
- async def send_control_command(self, command: str, args: Dict[str, Any]) -> bool:
220
+ async def send_control_command(self, command: str, args: dict[str, Any]) -> bool:
216
221
  """
217
222
  Sends a generic control command to the printer via HTTP POST.
218
-
223
+
219
224
  Args:
220
225
  command: The specific command string to send.
221
226
  args: The arguments or payload specific to the command.
222
-
227
+
223
228
  Returns:
224
229
  True if the command is acknowledged with a success code, False otherwise.
225
230
  """
226
231
  payload = {
227
232
  "serialNumber": self.client.serial_number,
228
233
  "checkCode": self.client.check_code,
229
- "payload": {
230
- "cmd": command,
231
- "args": args
232
- }
234
+ "payload": {"cmd": command, "args": args},
233
235
  }
234
236
 
235
237
  print(f"SendControlCommand:\n{payload}")
@@ -239,9 +241,9 @@ class Control:
239
241
 
240
242
  async with aiohttp.ClientSession() as session:
241
243
  async with session.post(
242
- self.client.get_endpoint(Endpoints.CONTROL),
243
- json=payload,
244
- headers={"Content-Type": "application/json"}
244
+ self.client.get_endpoint(Endpoints.CONTROL),
245
+ json=payload,
246
+ headers={"Content-Type": "application/json"},
245
247
  ) as response:
246
248
  # Fix for FlashForge printer's malformed Content-Type header
247
249
  # Some printers return "appliation/json" instead of "application/json"
@@ -251,6 +253,7 @@ class Control:
251
253
  # Fallback: manually parse as JSON if Content-Type is malformed
252
254
  text = await response.text()
253
255
  import json
256
+
254
257
  data = json.loads(text)
255
258
 
256
259
  print(f"Command reply: {data}")
@@ -266,36 +269,36 @@ class Control:
266
269
  async def send_job_control_cmd(self, command: str) -> bool:
267
270
  """
268
271
  Sends a job control command.
269
-
272
+
270
273
  Args:
271
274
  command: The job control command to send.
272
-
275
+
273
276
  Returns:
274
277
  True if the command is successful, False otherwise.
275
278
  """
276
279
  payload = {
277
280
  "jobID": "", # jobID seems to be optional or not strictly enforced
278
- "action": command
281
+ "action": command,
279
282
  }
280
283
 
281
284
  return await self.send_control_command(Commands.JOB_CONTROL_CMD, payload)
282
285
 
283
286
  async def _send_printer_control_cmd(
284
- self,
285
- z_offset: float = 0.0,
286
- print_speed: int = 100,
287
- chamber_fan_speed: int = 100,
288
- cooling_fan_speed: int = 100
287
+ self,
288
+ z_offset: float = 0.0,
289
+ print_speed: int = 100,
290
+ chamber_fan_speed: int = 100,
291
+ cooling_fan_speed: int = 100,
289
292
  ) -> bool:
290
293
  """
291
294
  Sends a command to control various printer settings during a print.
292
-
295
+
293
296
  Args:
294
297
  z_offset: The Z-axis compensation offset.
295
298
  print_speed: The print speed percentage.
296
299
  chamber_fan_speed: The chamber fan speed percentage.
297
300
  cooling_fan_speed: The cooling fan speed percentage.
298
-
301
+
299
302
  Returns:
300
303
  True if the command is successful, False otherwise.
301
304
  """
@@ -314,7 +317,7 @@ class Control:
314
317
  "speed": print_speed,
315
318
  "chamberFan": chamber_fan_speed,
316
319
  "coolingFan": cooling_fan_speed,
317
- "coolingLeftFan": 0 # This is unused
320
+ "coolingLeftFan": 0, # This is unused
318
321
  }
319
322
 
320
323
  return await self.send_control_command(Commands.PRINTER_CONTROL_CMD, payload)
@@ -322,22 +325,22 @@ class Control:
322
325
  async def _send_filtration_command(self, args: FilamentArgs) -> bool:
323
326
  """
324
327
  Sends a command to control the printer's filtration system.
325
-
328
+
326
329
  Args:
327
330
  args: The filtration arguments specifying internal and external fan states.
328
-
331
+
329
332
  Returns:
330
333
  True if the command is successful, False otherwise.
331
334
  """
332
- return await self.send_control_command(Commands.CIRCULATION_CONTROL_CMD, args.dict())
335
+ return await self.send_control_command(Commands.CIRCULATION_CONTROL_CMD, args.model_dump())
333
336
 
334
337
  async def _send_camera_command(self, enabled: bool) -> bool:
335
338
  """
336
339
  Sends a command to control the printer's camera.
337
-
340
+
338
341
  Args:
339
342
  enabled: True to turn the camera on ("open"), false to turn it off ("close").
340
-
343
+
341
344
  Returns:
342
345
  True if the command is successful, False otherwise.
343
346
  """