aiobambulab 0.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.
@@ -0,0 +1,122 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # OSX useful to ignore
7
+ *.DS_Store
8
+ .AppleDouble
9
+ .LSOverride
10
+
11
+ # Thumbnails
12
+ ._*
13
+
14
+ # Files that might appear in the root of a volume
15
+ .DocumentRevisions-V100
16
+ .fseventsd
17
+ .Spotlight-V100
18
+ .TemporaryItems
19
+ .Trashes
20
+ .VolumeIcon.icns
21
+ .com.apple.timemachine.donotpresent
22
+
23
+ # Directories potentially created on remote AFP share
24
+ .AppleDB
25
+ .AppleDesktop
26
+ Network Trash Folder
27
+ Temporary Items
28
+ .apdisk
29
+
30
+ # C extensions
31
+ *.so
32
+
33
+ # Distribution / packaging
34
+ .Python
35
+ env/
36
+ build/
37
+ develop-eggs/
38
+ dist/
39
+ downloads/
40
+ eggs/
41
+ .eggs/
42
+ lib/
43
+ lib64/
44
+ parts/
45
+ sdist/
46
+ var/
47
+ *.egg-info/
48
+ .installed.cfg
49
+ *.egg
50
+
51
+ # PyInstaller
52
+ # Usually these files are written by a python script from a template
53
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
54
+ *.manifest
55
+ *.spec
56
+
57
+ # Installer logs
58
+ pip-log.txt
59
+ pip-delete-this-directory.txt
60
+
61
+ # Unit test / coverage reports
62
+ htmlcov/
63
+ .tox/
64
+ .coverage
65
+ .coverage.*
66
+ .cache
67
+ nosetests.xml
68
+ coverage.xml
69
+ *,cover
70
+ .hypothesis/
71
+ .pytest_cache/
72
+
73
+ # Translations
74
+ *.mo
75
+ *.pot
76
+
77
+ # Django stuff:
78
+ *.log
79
+
80
+ # Sphinx documentation
81
+ docs/_build/
82
+
83
+ # pyenv
84
+ .python-version
85
+
86
+ # virtualenv
87
+ .venv
88
+ venv/
89
+ ENV/
90
+
91
+ # mypy
92
+ .mypy_cache/
93
+
94
+ # ruff
95
+ .ruff_cache
96
+
97
+ # Visual Studio Code
98
+ .vscode
99
+
100
+ # IntelliJ Idea family of suites
101
+ .idea
102
+ *.iml
103
+
104
+ ## File-based project format:
105
+ *.ipr
106
+ *.iws
107
+
108
+ ## mpeltonen/sbt-idea plugin
109
+ .idea_modules/
110
+
111
+ # PyBuilder
112
+ target/
113
+
114
+ # Cookiecutter
115
+ output/
116
+ python_boilerplate/
117
+
118
+ # Node
119
+ node_modules/
120
+
121
+ # Deepcode AI
122
+ .dccache
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joost Lekkerkerker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,336 @@
1
+ Metadata-Version: 2.5
2
+ Name: aiobambulab
3
+ Version: 0.0.1
4
+ Summary: Asynchronous Python client for Bambu Lab 3D printers on the local network
5
+ Project-URL: Homepage, https://github.com/joostlek/python-bambulab
6
+ Project-URL: Repository, https://github.com/joostlek/python-bambulab
7
+ Project-URL: Documentation, https://github.com/joostlek/python-bambulab
8
+ Project-URL: Bug Tracker, https://github.com/joostlek/python-bambulab/issues
9
+ Project-URL: Changelog, https://github.com/joostlek/python-bambulab/releases
10
+ Author-email: Joost Lekkerkerker <joostlek@outlook.com>
11
+ Maintainer-email: Joost Lekkerkerker <joostlek@outlook.com>
12
+ License-Expression: MIT
13
+ License-File: LICENSE.md
14
+ Keywords: 3d printer,asyncio,bambu lab,bambulab,mqtt
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Framework :: AsyncIO
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Natural Language :: English
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Home Automation
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: <4,>=3.13
26
+ Requires-Dist: aiomqtt>=2.5.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Python: Bambu Lab
30
+
31
+ [![GitHub Release][releases-shield]][releases]
32
+ [![Python Versions][python-versions-shield]][pypi]
33
+ ![Project Stage][project-stage-shield]
34
+ ![Project Maintenance][maintenance-shield]
35
+ [![License][license-shield]](LICENSE.md)
36
+
37
+ [![Build Status][build-shield]][build]
38
+ [![Code Coverage][codecov-shield]][codecov]
39
+ [![Code Smells][code-smells]][sonarcloud]
40
+
41
+ Asynchronous Python client for Bambu Lab 3D printers on the local network.
42
+
43
+ ## About
44
+
45
+ The client connects to the MQTT server that every Bambu Lab printer runs, and follows what the printer reports: the state of the print job, its progress, temperatures, and more. It does not use the Bambu Lab cloud.
46
+
47
+ - Fully asynchronous, built on [aiomqtt](https://github.com/empicano/aiomqtt). No threads.
48
+ - Push based: the printer tells the client what changed, and the client tells you.
49
+ - Typed models and typed errors.
50
+ - Verifies that it talks to your printer: it only accepts a certificate that Bambu Lab issued to the serial number you pass in.
51
+ - Connects again by itself when the connection is lost.
52
+ - Knows what the printer is doing in detail: the stage of the print job, fans, nozzle, errors, and the filament in each tray of an AMS.
53
+ - Sends commands: pause, resume, or stop a print, set the speed profile, temperatures, and fans, switch the light, and more.
54
+ - Gives you the camera: images for the printers that send images, and the address of the video stream for the printers that have one.
55
+ - Finds the printers on your network.
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install aiobambulab
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ### What you need
66
+
67
+ - The IP address of the printer.
68
+ - The serial number of the printer. It is not case sensitive.
69
+ - The LAN access code of the printer.
70
+
71
+ You find all three on the screen of the printer. The printer does not have to be in LAN only mode.
72
+
73
+ ### Finding printers
74
+
75
+ A printer announces itself on the network every few seconds. `discover()` listens for that, so you do not have to look up the IP address and the serial number:
76
+
77
+ ```python
78
+ from aiobambulab import discover
79
+
80
+ for printer in await discover():
81
+ print(printer.serial, printer.host, printer.name)
82
+ ```
83
+
84
+ It returns shortly after the last printer showed up, or after 15 seconds when there are none. The access code is not announced: that one you still read from the screen of the printer.
85
+
86
+ Announcements do not cross routers, so this only finds printers on the same network.
87
+
88
+ ### Connecting
89
+
90
+ ```python
91
+ import asyncio
92
+
93
+ from aiobambulab import BambuLabClient
94
+
95
+
96
+ async def main() -> None:
97
+ async with BambuLabClient("192.168.1.50", "01P00A000000001", "12345678") as client:
98
+ print(client.info.model_name, client.info.firmware_version)
99
+ print(client.state)
100
+
101
+ def on_change() -> None:
102
+ if not client.available:
103
+ print("The printer is gone")
104
+ return
105
+ print(client.state.print_state, client.state.progress)
106
+
107
+ remove_listener = client.add_listener(on_change)
108
+ await asyncio.sleep(3600)
109
+ remove_listener()
110
+
111
+
112
+ asyncio.run(main())
113
+ ```
114
+
115
+ `connect()`, which the context manager calls, returns once the client knows which printer it is and what its state is. From then on:
116
+
117
+ - `client.info` is what the printer is: its model, firmware version, and hardware version.
118
+ - `client.state` is what the printer is doing. A value is `None` when the printer does not report it. Temperatures are in whole degrees Celsius, like the printer shows them.
119
+ - `client.available` is `False` while the connection is lost. The client keeps trying to connect again, and `client.state` keeps the last known state.
120
+ - `client.error` is why the printer is not available, if that is known. The client keeps trying whatever the error is. An error like a rejected access code does not go away by itself, so act on it.
121
+ - Listeners are called when the state, the info, or the availability changes.
122
+
123
+ ### State
124
+
125
+ `client.state` is a `PrinterState`. Next to the print job and the temperatures, it holds:
126
+
127
+ - `stage`: what the printer is doing right now, like leveling its bed, changing filament, or being paused because the filament ran out. See `PrintStage`.
128
+ - `part_fan_speed`, `aux_fan_speed`, `chamber_fan_speed`, and `heatbreak_fan_speed`: the speed of each fan, as a percentage.
129
+ - `print_error`: the code of what went wrong with the print job, like `0700_8006`.
130
+ - `errors`: the problems the printer reports, each with the code that Bambu Lab calls an HMS code, and a severity.
131
+ - `ams`: the AMS units, each with its humidity, its temperature, and its trays. A tray has the `Filament` that is in it, with its type, name, color, and what remains of it. `active` tells which tray the printer prints from.
132
+ - `external_spool` and `external_spool_active`: the same for the spool that is not in an AMS.
133
+ - `nozzle_diameter` and `nozzle_type`.
134
+ - `timelapse_enabled` and `recording_enabled`: what the camera does during a print job.
135
+ - `sd_card_present`.
136
+ - `available_firmware_version`: the version the printer can update to, if there is one.
137
+
138
+ The texts that go with the codes of errors are not part of this library. Bambu Lab publishes them.
139
+
140
+ ### Commands
141
+
142
+ ```python
143
+ from aiobambulab import Fan, SpeedProfile
144
+
145
+ await client.set_chamber_light(on=True)
146
+ await client.pause_print()
147
+ await client.resume_print()
148
+ await client.stop_print()
149
+ await client.set_speed_profile(SpeedProfile.SILENT)
150
+ await client.set_nozzle_temperature(215)
151
+ await client.set_bed_temperature(60)
152
+ await client.set_fan_speed(Fan.PART_COOLING, 50)
153
+ await client.set_timelapse(enabled=True)
154
+ await client.set_recording(enabled=False)
155
+ await client.skip_objects([206])
156
+ await client.calibrate(bed_leveling=True)
157
+ await client.home()
158
+ await client.send_gcode("M400")
159
+ await client.refresh()
160
+ ```
161
+
162
+ Temperatures, fans, and homing are sent as G-code. Whether a printer accepts a G-code depends on its model and its firmware.
163
+
164
+ A command raises `BambuLabConnectionError` when the printer is not connected. The printer does not confirm a command in a way to rely on: what it did shows in the state it reports afterwards.
165
+
166
+ Newer firmware only accepts commands when the printer is in developer mode. `client.state.accepts_commands` tells whether it does. The light is the exception: the printer always accepts the command for it.
167
+
168
+ ### Camera
169
+
170
+ Printers have one of two kinds of camera access, depending on the model.
171
+
172
+ The A1 and P1 series, and the A2L, send images:
173
+
174
+ ```python
175
+ if client.supports_camera_images:
176
+ image = await client.camera_image() # A JPEG image
177
+ ```
178
+
179
+ The first image takes a moment, because the connection to the camera only opens when you ask for an image. It stays open while you keep asking, so the next images come right away. It closes when you stop asking for 30 seconds, and on `disconnect()`.
180
+
181
+ The other printers serve a video stream, when that is turned on on the printer:
182
+
183
+ ```python
184
+ if (url := client.camera_stream_url) is not None:
185
+ ... # An rtsps:// address for a video player. It holds the access code.
186
+ ```
187
+
188
+ `client.state.camera_stream_enabled` is `None` for a printer without a video stream, and `False` when the stream is turned off on the printer.
189
+
190
+ ### Errors
191
+
192
+ `connect()` raises one of these, all subclasses of `BambuLabError`:
193
+
194
+ | Error | Meaning |
195
+ | ----------------------------- | ------------------------------------------------------------------------- |
196
+ | `BambuLabAuthenticationError` | The printer rejected the access code. |
197
+ | `BambuLabSerialMismatchError` | The printer at this address has another serial number. |
198
+ | `BambuLabCertificateError` | The device at this address has no certificate issued by Bambu Lab. |
199
+ | `BambuLabConnectionError` | The printer could not be reached, or it did not report its state in time. |
200
+
201
+ `BambuLabSerialMismatchError` is a `BambuLabCertificateError`, which is a `BambuLabConnectionError`. Catch the specific ones first.
202
+
203
+ ### TLS
204
+
205
+ A printer serves a certificate that Bambu Lab issued to its serial number. By default, the client only trusts the certificate authorities of Bambu Lab, and checks the serial number in the certificate before it sends the access code.
206
+
207
+ To decide this yourself, pass your own `ssl.SSLContext` as `ssl_context`.
208
+
209
+ Creating the default context reads files from disk. The client does that in an executor. To create it yourself, for example to reuse it, call `create_ssl_context(serial)` in an executor.
210
+
211
+ ## What is not in this library
212
+
213
+ - Anything that goes through the Bambu Lab cloud.
214
+ - Starting a print job, and everything else that needs the files on the printer: uploading, the cover image of a print job, and downloading a timelapse.
215
+ - Loading and unloading filament, and drying it in an AMS.
216
+ - The second nozzle of a printer with two: temperatures are those of the nozzle in use.
217
+ - What only a few models have, like a laser, a cutter, a door sensor, or an air filter.
218
+ - Updating the firmware.
219
+
220
+ ## Changelog & Releases
221
+
222
+ This repository keeps a change log using [GitHub's releases][releases]
223
+ functionality. The format of the log is based on
224
+ [Keep a Changelog][keepchangelog].
225
+
226
+ Releases are based on [Semantic Versioning][semver], and use the format
227
+ of `MAJOR.MINOR.PATCH`. In a nutshell, the version will be incremented
228
+ based on the following:
229
+
230
+ - `MAJOR`: Incompatible or major changes.
231
+ - `MINOR`: Backwards-compatible new features and enhancements.
232
+ - `PATCH`: Backwards-compatible bugfixes and package updates.
233
+
234
+ ## Contributing
235
+
236
+ This is an active open-source project. We are always open to people who want to
237
+ use the code or contribute to it.
238
+
239
+ We've set up a separate document for our
240
+ [contribution guidelines](.github/CONTRIBUTING.md).
241
+
242
+ Thank you for being involved! :heart_eyes:
243
+
244
+ ## Setting up development environment
245
+
246
+ This Python project is fully managed using the [uv][uv] dependency manager. But also relies on the use of NodeJS for certain checks during development.
247
+
248
+ You need at least:
249
+
250
+ - Python 3.13+
251
+ - [uv][uv-install]
252
+ - NodeJS 12+ (including NPM)
253
+
254
+ To install all packages, including all development requirements:
255
+
256
+ ```bash
257
+ npm install
258
+ uv sync --all-groups
259
+ ```
260
+
261
+ As this repository uses the [prek][prek] framework, all changes
262
+ are linted and tested with each commit. You can run all checks and tests
263
+ manually, using the following command:
264
+
265
+ ```bash
266
+ uv run prek run --all-files
267
+ ```
268
+
269
+ To run just the Python tests:
270
+
271
+ ```bash
272
+ uv run pytest
273
+ ```
274
+
275
+ The tests run the client against a fake printer: a small MQTT server over TLS, in `tests/fake_printer.py`. Nothing in the tests is mocked between the client and the network.
276
+
277
+ ## Credits
278
+
279
+ The protocol of the printers is not documented by Bambu Lab. This library builds on what others found out and wrote down:
280
+
281
+ - [OpenBambuAPI](https://github.com/Doridian/OpenBambuAPI), the community documentation of the protocol.
282
+ - [ha-bambulab](https://github.com/greghesp/ha-bambulab), the custom integration for Home Assistant. The certificate authorities in `src/aiobambulab/certs/bambulab.pem` are the ones of Bambu Lab that this project collected.
283
+
284
+ This library is not affiliated with or endorsed by Bambu Lab.
285
+
286
+ ## Authors & contributors
287
+
288
+ The content is by [Joost Lekkerkerker][joostlek].
289
+
290
+ For a full list of all authors and contributors,
291
+ check [the contributor's page][contributors].
292
+
293
+ ## License
294
+
295
+ MIT License
296
+
297
+ Copyright (c) 2026 Joost Lekkerkerker
298
+
299
+ Permission is hereby granted, free of charge, to any person obtaining a copy
300
+ of this software and associated documentation files (the "Software"), to deal
301
+ in the Software without restriction, including without limitation the rights
302
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
303
+ copies of the Software, and to permit persons to whom the Software is
304
+ furnished to do so, subject to the following conditions:
305
+
306
+ The above copyright notice and this permission notice shall be included in all
307
+ copies or substantial portions of the Software.
308
+
309
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
310
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
311
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
312
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
313
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
314
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
315
+ SOFTWARE.
316
+
317
+ [build-shield]: https://github.com/joostlek/python-bambulab/actions/workflows/tests.yaml/badge.svg
318
+ [build]: https://github.com/joostlek/python-bambulab/actions
319
+ [code-smells]: https://sonarcloud.io/api/project_badges/measure?project=joostlek_python-bambulab&metric=code_smells
320
+ [codecov-shield]: https://codecov.io/gh/joostlek/python-bambulab/branch/main/graph/badge.svg
321
+ [codecov]: https://codecov.io/gh/joostlek/python-bambulab
322
+ [contributors]: https://github.com/joostlek/python-bambulab/graphs/contributors
323
+ [joostlek]: https://github.com/joostlek
324
+ [keepchangelog]: http://keepachangelog.com/en/1.0.0/
325
+ [license-shield]: https://img.shields.io/github/license/joostlek/python-bambulab.svg
326
+ [maintenance-shield]: https://img.shields.io/maintenance/yes/2026.svg
327
+ [uv-install]: https://docs.astral.sh/uv/getting-started/installation/
328
+ [uv]: https://docs.astral.sh/uv/
329
+ [prek]: https://prek.j178.dev/
330
+ [project-stage-shield]: https://img.shields.io/badge/project%20stage-beta-yellow.svg
331
+ [python-versions-shield]: https://img.shields.io/pypi/pyversions/aiobambulab
332
+ [releases-shield]: https://img.shields.io/github/release/joostlek/python-bambulab.svg
333
+ [releases]: https://github.com/joostlek/python-bambulab/releases
334
+ [semver]: http://semver.org/spec/v2.0.0.html
335
+ [sonarcloud]: https://sonarcloud.io/summary/new_code?id=joostlek_python-bambulab
336
+ [pypi]: https://pypi.org/project/aiobambulab/