flashforge-python-api 1.0.0__tar.gz → 1.0.1__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.
Files changed (81) hide show
  1. flashforge_python_api-1.0.1/.github/workflows/publish.yml +141 -0
  2. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/.gitignore +3 -0
  3. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/CHANGELOG.md +5 -0
  4. flashforge_python_api-1.0.1/CLAUDE.md +25 -0
  5. flashforge_python_api-1.0.1/PKG-INFO +211 -0
  6. flashforge_python_api-1.0.1/README.md +162 -0
  7. flashforge_python_api-1.0.1/docs/README.md +87 -0
  8. flashforge_python_api-1.0.1/docs/advanced.md +93 -0
  9. flashforge_python_api-1.0.1/docs/api_reference.md +75 -0
  10. flashforge_python_api-1.0.1/docs/client.md +123 -0
  11. flashforge_python_api-1.0.1/docs/models.md +91 -0
  12. flashforge_python_api-1.0.1/docs/protocols.md +63 -0
  13. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/controls/files.py +19 -3
  14. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/client.py +1 -0
  15. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/models/machine_info.py +2 -2
  16. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/pyproject.toml +1 -1
  17. flashforge_python_api-1.0.1/tests/fixtures/printer_responses.py +145 -0
  18. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/printer_config.py +22 -1
  19. flashforge_python_api-1.0.1/tests/test_5m_pro_live_integration.py +80 -0
  20. flashforge_python_api-1.0.1/tests/test_additional_parsers.py +87 -0
  21. flashforge_python_api-1.0.1/tests/test_client.py +182 -0
  22. flashforge_python_api-1.0.1/tests/test_control.py +128 -0
  23. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/test_discovery.py +116 -11
  24. flashforge_python_api-1.0.1/tests/test_files.py +217 -0
  25. flashforge_python_api-1.0.1/tests/test_info.py +102 -0
  26. flashforge_python_api-1.0.1/tests/test_job_control.py +199 -0
  27. flashforge_python_api-1.0.1/tests/test_tcp_client.py +156 -0
  28. flashforge_python_api-1.0.1/tests/test_temp_control.py +111 -0
  29. flashforge_python_api-1.0.0/PKG-INFO +0 -123
  30. flashforge_python_api-1.0.0/README.md +0 -74
  31. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/.claude/commands/push.md +0 -0
  32. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/.claude/settings.local.json +0 -0
  33. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/LICENSE +0 -0
  34. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/ai_specs/TEST_COVERAGE_SPEC.md +0 -0
  35. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/examples/complete_feature_demo.py +0 -0
  36. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/examples/discovery_example.py +0 -0
  37. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/examples/tcp_client_example.py +0 -0
  38. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/examples/unified_client_example.py +0 -0
  39. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/__init__.py +0 -0
  40. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/__init__.py +0 -0
  41. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/constants/__init__.py +0 -0
  42. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/constants/commands.py +0 -0
  43. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/constants/endpoints.py +0 -0
  44. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/controls/__init__.py +0 -0
  45. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/controls/control.py +0 -0
  46. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/controls/info.py +0 -0
  47. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/controls/job_control.py +0 -0
  48. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/controls/temp_control.py +0 -0
  49. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/filament/__init__.py +0 -0
  50. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/filament/filament.py +0 -0
  51. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/misc/__init__.py +0 -0
  52. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/misc/scientific_notation.py +0 -0
  53. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/misc/temperature.py +0 -0
  54. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/network/__init__.py +0 -0
  55. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/network/fnet_code.py +0 -0
  56. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/api/network/utils.py +0 -0
  57. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/discovery/__init__.py +0 -0
  58. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/discovery/discovery.py +0 -0
  59. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/models/__init__.py +0 -0
  60. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/models/responses.py +0 -0
  61. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/__init__.py +0 -0
  62. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/ff_client.py +0 -0
  63. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/gcode/__init__.py +0 -0
  64. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/gcode/gcode_controller.py +0 -0
  65. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/gcode/gcodes.py +0 -0
  66. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/__init__.py +0 -0
  67. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/endstop_status.py +0 -0
  68. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/location_info.py +0 -0
  69. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/print_status.py +0 -0
  70. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/printer_info.py +0 -0
  71. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/temp_info.py +0 -0
  72. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/parsers/thumbnail_info.py +0 -0
  73. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/flashforge/tcp/tcp_client.py +0 -0
  74. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/__init__.py +0 -0
  75. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/conftest.py +0 -0
  76. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/run_tests.py +0 -0
  77. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/test_ad5x_job_control.py +0 -0
  78. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/test_ad5x_live_integration.py +0 -0
  79. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/test_ad5x_models.py +0 -0
  80. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/test_parsers.py +0 -0
  81. {flashforge_python_api-1.0.0 → flashforge_python_api-1.0.1}/tests/test_utility_classes.py +0 -0
@@ -0,0 +1,141 @@
1
+ name: Publish to GitHub Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: 'Version to release (e.g., 1.0.1). Leave empty to auto-generate timestamped version (e.g. 1.0.0-2023...) if tag exists.'
8
+ required: false
9
+ type: string
10
+
11
+ permissions:
12
+ contents: write
13
+
14
+ jobs:
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+
18
+ steps:
19
+ - name: Checkout repository
20
+ uses: actions/checkout@v4
21
+ with:
22
+ fetch-depth: 0
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: '3.12'
28
+
29
+ - name: Install Hatch
30
+ run: |
31
+ pip install hatch
32
+
33
+ - name: Determine and Update Version
34
+ id: version
35
+ shell: python
36
+ env:
37
+ INPUT_VERSION: ${{ inputs.version }}
38
+ REF_NAME: ${{ github.ref_name }}
39
+ run: |
40
+ import os
41
+ import re
42
+ import subprocess
43
+ import sys
44
+ from datetime import datetime
45
+
46
+ def get_current_version():
47
+ with open("pyproject.toml", "r") as f:
48
+ content = f.read()
49
+ match = re.search(r'version\s*=\s*["\']([^"\']+)["\']', content)
50
+ if match:
51
+ return match.group(1)
52
+ sys.exit("Could not find version in pyproject.toml")
53
+
54
+ def update_pyproject(new_version):
55
+ with open("pyproject.toml", "r") as f:
56
+ content = f.read()
57
+
58
+ new_content = re.sub(r'version\s*=\s*["\'][^"\']+["\']', f'version = "{new_version}"', content, count=1)
59
+
60
+ with open("pyproject.toml", "w") as f:
61
+ f.write(new_content)
62
+ print(f"Updated pyproject.toml to version {new_version}")
63
+
64
+ def tag_exists(tag):
65
+ try:
66
+ subprocess.check_output(["git", "rev-parse", tag], stderr=subprocess.STDOUT)
67
+ return True
68
+ except subprocess.CalledProcessError:
69
+ return False
70
+
71
+ input_version = os.environ.get("INPUT_VERSION")
72
+ ref_name = os.environ.get("REF_NAME")
73
+ current_version = get_current_version()
74
+ print(f"Current version in pyproject.toml: {current_version}")
75
+
76
+ new_version = current_version
77
+ should_commit = False
78
+ should_push_commit = False
79
+
80
+ if input_version:
81
+ # Manual version input
82
+ if input_version != current_version:
83
+ new_version = input_version
84
+ should_commit = True
85
+ should_push_commit = True
86
+ print(f"Using input version: {new_version} (Will update, commit, and push)")
87
+ else:
88
+ print("Input version matches current version. (No file change needed)")
89
+ else:
90
+ # No input - Check for existing tag
91
+ tag = f"v{current_version}"
92
+ if tag_exists(tag):
93
+ # Tag exists, generate timestamp version
94
+ timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
95
+ new_version = f"{current_version}-{timestamp}"
96
+ should_commit = True
97
+ should_push_commit = False # Do not push ephemeral version to main
98
+ print(f"Tag {tag} exists. Generated timestamp version: {new_version} (Will commit locally but NOT push to branch)")
99
+ else:
100
+ print(f"Tag {tag} does not exist. Using current version: {current_version} (First release of this version)")
101
+
102
+ # Configure git
103
+ subprocess.run(["git", "config", "user.name", "github-actions[bot]"], check=True)
104
+ subprocess.run(["git", "config", "user.email", "github-actions[bot]@users.noreply.github.com"], check=True)
105
+
106
+ if should_commit:
107
+ update_pyproject(new_version)
108
+ subprocess.run(["git", "add", "pyproject.toml"], check=True)
109
+ subprocess.run(["git", "commit", "-m", f"Release {new_version}"], check=True)
110
+
111
+ if should_push_commit:
112
+ # Pull changes to avoid conflicts before pushing
113
+ subprocess.run(["git", "fetch", "origin", ref_name], check=True)
114
+ subprocess.run(["git", "pull", "--rebase", "origin", ref_name], check=True)
115
+ # Push to specific branch
116
+ subprocess.run(["git", "push", "origin", f"HEAD:{ref_name}"], check=True)
117
+ else:
118
+ print("Skipping push of commit (Ephemeral/Timestamp release).")
119
+
120
+ # Create tag if it doesn't exist
121
+ tag_name = f"v{new_version}"
122
+ if not tag_exists(tag_name):
123
+ print(f"Creating tag {tag_name}")
124
+ subprocess.run(["git", "tag", tag_name], check=True)
125
+ subprocess.run(["git", "push", "origin", tag_name], check=True)
126
+ else:
127
+ print(f"Tag {tag_name} already exists.")
128
+
129
+ with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
130
+ fh.write(f"version={new_version}\n")
131
+
132
+ - name: Build
133
+ run: hatch build
134
+
135
+ - name: Create Release
136
+ uses: softprops/action-gh-release@v2
137
+ with:
138
+ tag_name: v${{ steps.version.outputs.version }}
139
+ name: Release ${{ steps.version.outputs.version }}
140
+ files: dist/*
141
+ generate_release_notes: true
@@ -116,3 +116,6 @@ coverage.xml
116
116
  thumb_*.png
117
117
  thumbnail_*.png
118
118
  test_*.png
119
+
120
+ # PyPI credentials
121
+ .pypirc
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.1] - 2025-12-24
9
+
10
+ ### Fixed
11
+ - Fixed Pydantic validation error for `estimated_time` field in `FFPrinterDetail` and `FFMachineInfo` models. Changed type from `int` to `float` to handle printer API responses that return fractional time values.
12
+
8
13
  ## [1.0.0] - 2025-01-02
9
14
 
10
15
  ### Added
@@ -0,0 +1,25 @@
1
+ # Claude Development Notes
2
+
3
+ ## PyPI Publishing
4
+
5
+ ### Configuration Files
6
+ - `.pypirc` - Contains PyPI authentication token for publishing packages
7
+ - Location: Project root directory
8
+ - Status: Git-ignored (not tracked in version control)
9
+ - Contains username and API token for automated PyPI uploads
10
+ - Note: This file exists locally but won't be visible in git status
11
+
12
+ ### Publishing to PyPI
13
+ To publish a new version:
14
+
15
+ 1. Update version in `pyproject.toml`
16
+ 2. Clean previous builds: `rm -rf dist/ build/ *.egg-info`
17
+ 3. Build: `python -m build`
18
+ 4. Upload: `python -m twine upload dist/*`
19
+ - Credentials will be read automatically from `.pypirc`
20
+
21
+ ### Package Info
22
+ - Package name: `flashforge-python-api`
23
+ - PyPI URL: https://pypi.org/project/flashforge-python-api/
24
+ - Build system: Hatchling
25
+ - Current version: 1.0.0
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: flashforge-python-api
3
+ Version: 1.0.1
4
+ Summary: A comprehensive Python library for controlling FlashForge 3D printers
5
+ Project-URL: Homepage, https://github.com/GhostTypes/ff-5mp-api-py
6
+ Project-URL: Documentation, https://github.com/GhostTypes/ff-5mp-api-py#readme
7
+ Project-URL: Repository, https://github.com/GhostTypes/ff-5mp-api-py.git
8
+ Project-URL: Issues, https://github.com/GhostTypes/ff-5mp-api-py/issues
9
+ Author-email: GhostTypes <notghosttypes@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: 3d-printer,api,async,control,flashforge,python
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
24
+ Requires-Python: >=3.8
25
+ Requires-Dist: aiohttp>=3.8.0
26
+ Requires-Dist: netifaces>=0.11.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: requests>=2.31.0
29
+ Provides-Extra: all
30
+ Requires-Dist: black>=23.0.0; extra == 'all'
31
+ Requires-Dist: mypy>=1.0.0; extra == 'all'
32
+ Requires-Dist: pillow>=10.0.0; extra == 'all'
33
+ Requires-Dist: pre-commit>=3.0.0; extra == 'all'
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'all'
35
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
36
+ Requires-Dist: pytest>=7.0.0; extra == 'all'
37
+ Requires-Dist: ruff>=0.1.0; extra == 'all'
38
+ Provides-Extra: dev
39
+ Requires-Dist: black>=23.0.0; extra == 'dev'
40
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
41
+ Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
42
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
43
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
44
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
45
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
46
+ Provides-Extra: imaging
47
+ Requires-Dist: pillow>=10.0.0; extra == 'imaging'
48
+ Description-Content-Type: text/markdown
49
+
50
+ <div align="center">
51
+
52
+ # FlashForge Python API
53
+
54
+ A comprehensive Python library for controlling FlashForge 3D printers.
55
+
56
+ [![PyPI](https://img.shields.io/pypi/v/flashforge-python-api?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/flashforge-python-api/)
57
+ [![Python](https://img.shields.io/badge/Python-3.8%2B-blue?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/)
58
+ [![License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge&logo=opensourceinitiative&logoColor=white)](LICENSE)
59
+
60
+ </div>
61
+
62
+ <div align="center">
63
+
64
+ ## Features & Capabilities
65
+
66
+ | Feature | Description |
67
+ | :--- | :--- |
68
+ | **Printer Discovery** | Automatic UDP broadcast discovery of printers on the network |
69
+ | **Full Control** | Movement (G1), Homing (G28), Temperature (M104/M140), Fans, LED |
70
+ | **Real-time Monitoring** | Live status (M119), Temperatures (M105), Print Progress (M27) |
71
+ | **Job Management** | Start, Pause, Resume, Cancel, File Upload & Listing |
72
+ | **Advanced Parsing** | Thumbnail extraction (M662), Endstop monitoring, Machine state |
73
+ | **Dual Protocol** | Modern HTTP API + Legacy TCP G-code support |
74
+ | **Async Support** | Native async/await implementation for all operations |
75
+ | **Type Safety** | Full type hints and Pydantic models for robust development |
76
+
77
+ <br>
78
+
79
+ ## Supported Hardware
80
+
81
+ | Model | Support Level | Connection Type |
82
+ | :--- | :--- | :--- |
83
+ | **FlashForge Adventurer 5M / 5M Pro** | Full Support | HTTP + TCP |
84
+ | **FlashForge Adventurer 5X** | Full Support | HTTP + TCP |
85
+ | **FlashForge Adventurer 3 / 4** | Partial Support | TCP (Legacy) |
86
+ | **Other Networked FlashForge Printers** | Experimental | TCP (Generic) |
87
+
88
+ <br>
89
+
90
+ ## Compatible Slicers
91
+
92
+ | Slicer | Compatibility | Notes |
93
+ | :--- | :--- | :--- |
94
+ | **OrcaSlicer** | High | Recommended for Adventurer 5M series |
95
+ | **FlashPrint** | Full | Official FlashForge slicer |
96
+ | **Orca-FlashForge** | High | Optimized for FlashForge printers |
97
+ | **Cura / PrusaSlicer** | Basic | Requires correct G-code flavor |
98
+
99
+ <br>
100
+
101
+ ## Installation
102
+
103
+ | Command |
104
+ | :--- |
105
+ | `pip install flashforge-python-api` |
106
+
107
+ </div>
108
+
109
+ <div align="center">
110
+ <h2>Usage Examples</h2>
111
+ </div>
112
+
113
+ <div align="center">
114
+ <h3>Printer Discovery</h3>
115
+ Discover printers on your local network automatically.
116
+ </div>
117
+
118
+ ```python
119
+ from flashforge import FlashForgePrinterDiscovery
120
+ import asyncio
121
+
122
+ async def discover():
123
+ discovery = FlashForgePrinterDiscovery()
124
+ printers = await discovery.discover_printers_async()
125
+ for printer in printers:
126
+ print(f"Found: {printer.name} at {printer.ip_address}")
127
+
128
+ asyncio.run(discover())
129
+ ```
130
+
131
+ <div align="center">
132
+ <h3>Basic Control</h3>
133
+ Connect to a printer and perform basic operations like setting temperature and homing.
134
+ </div>
135
+
136
+ ```python
137
+ from flashforge import FlashForgeClient
138
+ import asyncio
139
+
140
+ async def control_printer():
141
+ # Initialize client with printer details
142
+ client = FlashForgeClient("192.168.1.100", "SERIAL_NUMBER", "CHECK_CODE")
143
+
144
+ if await client.initialize():
145
+ print(f"Connected to {client.printer_name}")
146
+
147
+ # Set bed temperature to 60°C
148
+ await client.temp_control.set_bed_temp(60)
149
+
150
+ # Home all axes
151
+ await client.control.home_xyz()
152
+
153
+ await client.dispose()
154
+
155
+ asyncio.run(control_printer())
156
+ ```
157
+
158
+ <div align="center">
159
+ <h3>Real-time Status Monitoring</h3>
160
+ Monitor printer status, temperatures, and print progress.
161
+ </div>
162
+
163
+ ```python
164
+ from flashforge import FlashForgeClient
165
+ import asyncio
166
+
167
+ async def monitor_printer():
168
+ async with FlashForgeClient("192.168.1.100", "SERIAL", "CODE") as client:
169
+ # Get comprehensive status
170
+ status = await client.get_printer_status()
171
+ print(f"Machine State: {status.machine_state}")
172
+
173
+ # Get temperatures via TCP
174
+ temps = await client.tcp_client.get_temp_info()
175
+ if temps:
176
+ bed = temps.get_bed_temp()
177
+ extruder = temps.get_extruder_temp()
178
+ print(f"Bed: {bed.get_current()}°C / {bed.get_target()}°C")
179
+ print(f"Extruder: {extruder.get_current()}°C / {extruder.get_target()}°C")
180
+
181
+ # Check print progress
182
+ layer_p, sd_p, current_layer = await client.tcp_client.get_print_progress()
183
+ print(f"Progress: {layer_p}% (Layer {current_layer})")
184
+
185
+ asyncio.run(monitor_printer())
186
+ ```
187
+
188
+ <div align="center">
189
+ <h3>File Operations & Thumbnails</h3>
190
+ List files on the printer and extract thumbnails.
191
+ </div>
192
+
193
+ ```python
194
+ from flashforge import FlashForgeClient
195
+ import asyncio
196
+
197
+ async def file_ops():
198
+ async with FlashForgeClient("192.168.1.100", "SERIAL", "CODE") as client:
199
+ # List files
200
+ files = await client.files.get_file_list()
201
+ for filename in files:
202
+ print(f"File: {filename}")
203
+
204
+ # Get thumbnail
205
+ thumb = await client.tcp_client.get_thumbnail(filename)
206
+ if thumb and thumb.has_image_data():
207
+ print(f"Thumbnail found: {len(thumb.get_image_bytes())} bytes")
208
+ # thumb.save_to_file_sync(f"{filename}.png")
209
+
210
+ asyncio.run(file_ops())
211
+ ```
@@ -0,0 +1,162 @@
1
+ <div align="center">
2
+
3
+ # FlashForge Python API
4
+
5
+ A comprehensive Python library for controlling FlashForge 3D printers.
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/flashforge-python-api?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/flashforge-python-api/)
8
+ [![Python](https://img.shields.io/badge/Python-3.8%2B-blue?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/)
9
+ [![License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge&logo=opensourceinitiative&logoColor=white)](LICENSE)
10
+
11
+ </div>
12
+
13
+ <div align="center">
14
+
15
+ ## Features & Capabilities
16
+
17
+ | Feature | Description |
18
+ | :--- | :--- |
19
+ | **Printer Discovery** | Automatic UDP broadcast discovery of printers on the network |
20
+ | **Full Control** | Movement (G1), Homing (G28), Temperature (M104/M140), Fans, LED |
21
+ | **Real-time Monitoring** | Live status (M119), Temperatures (M105), Print Progress (M27) |
22
+ | **Job Management** | Start, Pause, Resume, Cancel, File Upload & Listing |
23
+ | **Advanced Parsing** | Thumbnail extraction (M662), Endstop monitoring, Machine state |
24
+ | **Dual Protocol** | Modern HTTP API + Legacy TCP G-code support |
25
+ | **Async Support** | Native async/await implementation for all operations |
26
+ | **Type Safety** | Full type hints and Pydantic models for robust development |
27
+
28
+ <br>
29
+
30
+ ## Supported Hardware
31
+
32
+ | Model | Support Level | Connection Type |
33
+ | :--- | :--- | :--- |
34
+ | **FlashForge Adventurer 5M / 5M Pro** | Full Support | HTTP + TCP |
35
+ | **FlashForge Adventurer 5X** | Full Support | HTTP + TCP |
36
+ | **FlashForge Adventurer 3 / 4** | Partial Support | TCP (Legacy) |
37
+ | **Other Networked FlashForge Printers** | Experimental | TCP (Generic) |
38
+
39
+ <br>
40
+
41
+ ## Compatible Slicers
42
+
43
+ | Slicer | Compatibility | Notes |
44
+ | :--- | :--- | :--- |
45
+ | **OrcaSlicer** | High | Recommended for Adventurer 5M series |
46
+ | **FlashPrint** | Full | Official FlashForge slicer |
47
+ | **Orca-FlashForge** | High | Optimized for FlashForge printers |
48
+ | **Cura / PrusaSlicer** | Basic | Requires correct G-code flavor |
49
+
50
+ <br>
51
+
52
+ ## Installation
53
+
54
+ | Command |
55
+ | :--- |
56
+ | `pip install flashforge-python-api` |
57
+
58
+ </div>
59
+
60
+ <div align="center">
61
+ <h2>Usage Examples</h2>
62
+ </div>
63
+
64
+ <div align="center">
65
+ <h3>Printer Discovery</h3>
66
+ Discover printers on your local network automatically.
67
+ </div>
68
+
69
+ ```python
70
+ from flashforge import FlashForgePrinterDiscovery
71
+ import asyncio
72
+
73
+ async def discover():
74
+ discovery = FlashForgePrinterDiscovery()
75
+ printers = await discovery.discover_printers_async()
76
+ for printer in printers:
77
+ print(f"Found: {printer.name} at {printer.ip_address}")
78
+
79
+ asyncio.run(discover())
80
+ ```
81
+
82
+ <div align="center">
83
+ <h3>Basic Control</h3>
84
+ Connect to a printer and perform basic operations like setting temperature and homing.
85
+ </div>
86
+
87
+ ```python
88
+ from flashforge import FlashForgeClient
89
+ import asyncio
90
+
91
+ async def control_printer():
92
+ # Initialize client with printer details
93
+ client = FlashForgeClient("192.168.1.100", "SERIAL_NUMBER", "CHECK_CODE")
94
+
95
+ if await client.initialize():
96
+ print(f"Connected to {client.printer_name}")
97
+
98
+ # Set bed temperature to 60°C
99
+ await client.temp_control.set_bed_temp(60)
100
+
101
+ # Home all axes
102
+ await client.control.home_xyz()
103
+
104
+ await client.dispose()
105
+
106
+ asyncio.run(control_printer())
107
+ ```
108
+
109
+ <div align="center">
110
+ <h3>Real-time Status Monitoring</h3>
111
+ Monitor printer status, temperatures, and print progress.
112
+ </div>
113
+
114
+ ```python
115
+ from flashforge import FlashForgeClient
116
+ import asyncio
117
+
118
+ async def monitor_printer():
119
+ async with FlashForgeClient("192.168.1.100", "SERIAL", "CODE") as client:
120
+ # Get comprehensive status
121
+ status = await client.get_printer_status()
122
+ print(f"Machine State: {status.machine_state}")
123
+
124
+ # Get temperatures via TCP
125
+ temps = await client.tcp_client.get_temp_info()
126
+ if temps:
127
+ bed = temps.get_bed_temp()
128
+ extruder = temps.get_extruder_temp()
129
+ print(f"Bed: {bed.get_current()}°C / {bed.get_target()}°C")
130
+ print(f"Extruder: {extruder.get_current()}°C / {extruder.get_target()}°C")
131
+
132
+ # Check print progress
133
+ layer_p, sd_p, current_layer = await client.tcp_client.get_print_progress()
134
+ print(f"Progress: {layer_p}% (Layer {current_layer})")
135
+
136
+ asyncio.run(monitor_printer())
137
+ ```
138
+
139
+ <div align="center">
140
+ <h3>File Operations & Thumbnails</h3>
141
+ List files on the printer and extract thumbnails.
142
+ </div>
143
+
144
+ ```python
145
+ from flashforge import FlashForgeClient
146
+ import asyncio
147
+
148
+ async def file_ops():
149
+ async with FlashForgeClient("192.168.1.100", "SERIAL", "CODE") as client:
150
+ # List files
151
+ files = await client.files.get_file_list()
152
+ for filename in files:
153
+ print(f"File: {filename}")
154
+
155
+ # Get thumbnail
156
+ thumb = await client.tcp_client.get_thumbnail(filename)
157
+ if thumb and thumb.has_image_data():
158
+ print(f"Thumbnail found: {len(thumb.get_image_bytes())} bytes")
159
+ # thumb.save_to_file_sync(f"{filename}.png")
160
+
161
+ asyncio.run(file_ops())
162
+ ```
@@ -0,0 +1,87 @@
1
+ # FlashForge API Documentation
2
+
3
+ Welcome to the documentation for the FlashForge Python API. This library provides a comprehensive interface for controlling and monitoring FlashForge 3D printers, including the Adventurer 5M and 5M Pro series.
4
+
5
+ ## Overview
6
+
7
+ The FlashForge API allows you to interact with your printer using both TCP and HTTP protocols. It provides a unified client that handles connection management, command execution, and status monitoring.
8
+
9
+ ## Key Features
10
+
11
+ - **Unified Client**: A single entry point (`FlashForgeClient`) for all printer operations.
12
+ - **Automatic Discovery**: Find printers on your local network automatically.
13
+ - **Full Control**: Manage print jobs, movement, temperature, fans, LEDs, and more.
14
+ - **Real-time Monitoring**: Get detailed status updates, including temperatures, progress, and camera feed URL.
15
+ - **File Management**: List, upload, and delete files on the printer.
16
+ - **Type Safety**: Fully typed with Pydantic models for robust data handling.
17
+ - **Async Support**: Built on `asyncio` for efficient non-blocking operations.
18
+
19
+ ## Navigation
20
+
21
+ - [Getting Started](#getting-started)
22
+ - [Client API](client.md): Documentation for the main `FlashForgeClient` and `FlashForgePrinterDiscovery`.
23
+ - [Data Models](models.md): Detailed reference for all data objects (MachineInfo, Temperature, etc.).
24
+ - [Protocols](protocols.md): Understanding the underlying TCP and HTTP protocols.
25
+ - [Advanced Topics](advanced.md): Async patterns, error handling, and more.
26
+ - [API Reference](api_reference.md): Complete list of classes and methods.
27
+
28
+ ## Getting Started
29
+
30
+ ### Installation
31
+
32
+ ```bash
33
+ pip install flashforge-api
34
+ ```
35
+
36
+ ### Basic Usage
37
+
38
+ Here's a simple example of how to discover a printer and connect to it:
39
+
40
+ ```python
41
+ import asyncio
42
+ from flashforge import FlashForgePrinterDiscovery, FlashForgeClient
43
+
44
+ async def main():
45
+ # 1. Discover printers
46
+ discovery = FlashForgePrinterDiscovery()
47
+ printers = await discovery.discover_printers_async()
48
+
49
+ if not printers:
50
+ print("No printers found.")
51
+ return
52
+
53
+ printer_info = printers[0]
54
+ print(f"Found printer: {printer_info.name} at {printer_info.ip_address}")
55
+
56
+ # 2. Connect to the printer
57
+ # Note: 'check_code' is currently unused by some printers but required by the constructor
58
+ client = FlashForgeClient(printer_info.ip_address, printer_info.serial_number, check_code="")
59
+
60
+ await client.initialize()
61
+
62
+ # 3. Get printer status
63
+ status = await client.get_printer_status()
64
+ print(f"Status: {status.machine_state}")
65
+ print(f"Bed Temp: {status.print_bed.current}°C")
66
+ print(f"Nozzle Temp: {status.extruder.current}°C")
67
+
68
+ # 4. Clean up
69
+ await client.dispose()
70
+
71
+ if __name__ == "__main__":
72
+ asyncio.run(main())
73
+ ```
74
+
75
+ ### Context Manager Support
76
+
77
+ The client supports Python's async context manager protocol for automatic resource management:
78
+
79
+ ```python
80
+ async with FlashForgeClient(ip, serial, check_code="") as client:
81
+ status = await client.get_printer_status()
82
+ print(f"Ready: {status.machine_state == 'ready'}")
83
+ ```
84
+
85
+ ## Support
86
+
87
+ If you encounter any issues or have questions, please check the [Issues](https://github.com/yourusername/flashforge-api/issues) page on GitHub.