hopex / bambulab-sdk
Typed PHP SDK for local control and monitoring of Bambu Lab 3D printers.
Requires
- php: ^8.4
- ext-curl: *
- ext-json: *
- ext-openssl: *
- php-mqtt/client: ^2.3
Requires (Dev)
- phpunit/phpunit: ^12.0
This package is auto-updated.
Last update: 2026-08-02 10:03:54 UTC
README
Bambu Lab API для PHP
Полностью типизированный PHP 8.4 SDK для локального управления принтерами Bambu Lab.
Пакет предоставляет типизированный API для работы с состоянием принтера, заданиями печати, файлами, камерой, температурой, вентиляторами, подсветкой, прошивкой, HMS-сообщениями и событиями в реальном времени.
Проект является неофициальным SDK сообщества и не связан с Bambu Lab.
Возможности
- MQTT
- FTPS
- Camera
- Printer State
- Events
- Firmware
- HMS
- Files
- Temperature
- Fans
- Light
- Automatic reconnect
Требования
- PHP 8.4 или новее;
- расширение
ext-curl; - расширение
ext-json; - расширение
ext-openssl; - доступ к принтеру по локальной сети;
- включённый LAN Mode;
- действующий Access Code принтера.
SDK использует несколько локальных сервисов принтера:
- MQTT для команд и состояния;
- FTPS для работы с файлами;
- отдельное TLS-соединение для камеры.
Поддержка конкретных возможностей зависит от модели принтера и версии прошивки.
Установка
composer require hopex/bambulab-sdk
Настройка принтера
Перед использованием SDK:
- Подключите принтер и PHP-приложение к одной локальной сети.
- Включите LAN Mode в настройках принтера.
- Получите Access Code.
- Определите локальный IP-адрес принтера.
- Получите серийный номер принтера.
Не рекомендуется открывать MQTT, FTPS и порт камеры напрямую в интернет.
Быстрый старт
<?php declare(strict_types=1); use Hopex\BambuLab\BambuClient; use Hopex\BambuLab\Printer\DTO\PrinterCredentials; use Hopex\BambuLab\Transport\MqttTransport; require __DIR__ . '/vendor/autoload.php'; $credentials = new PrinterCredentials( host: '192.168.1.100', accessCode: 'ACCESS_CODE', serialNumber: 'SERIAL_NUMBER', ); $client = new BambuClient( credentials: $credentials, transport: new MqttTransport(), ); try { $client->connect(); if (!$client->waitUntilReady(timeoutSeconds: 15)) { throw new RuntimeException( 'Не удалось синхронизировать состояние принтера.', ); } $status = $client->state()->status(); echo sprintf( "Состояние: %s\n", $status->state?->value ?? 'UNKNOWN', ); echo sprintf( "Сопло: %.1f °C\n", $status->nozzleTemperature ?? 0, ); echo sprintf( "Стол: %.1f °C\n", $status->bedTemperature ?? 0, ); } finally { $client->disconnect(); }
Жизненный цикл клиента
Подключение
$client->connect();
По умолчанию клиент активирует MQTT-подписку и запрашивает полное состояние принтера.
Подключение без автоматического запроса состояния:
$client->connect(synchronize: false);
Обработка входящих сообщений
Одна итерация MQTT-цикла:
$client->tick();
Блокирующий цикл:
$client->run();
Остановка активного цикла:
$client->stop();
Отключение
$client->disconnect();
Состояние принтера
PrinterState хранит накопленное состояние принтера.
Принтер часто отправляет только изменившиеся поля. SDK рекурсивно объединяет частичные сообщения с ранее полученным состоянием.
$state = $client->state(); $status = $state->status(); echo $status->progress(); echo $status->remainingMinutes(); echo $status->currentLayer(); echo $status->totalLayers(); echo $status->bedTemperature(); echo $status->nozzleTemperature();
Получение полного накопленного payload:
$raw = $client->state()->raw();
Текущее задание печати
Текущее задание представлено объектом CurrentPrintJob.
$job = $client->state()->currentJob(); if ($job !== null) { echo $job->fileName; echo $job->name; echo $job->printType; echo $job->progress; echo $job->remainingMinutes; echo $job->currentLayer; echo $job->totalLayers; }
Доступные вспомогательные методы:
$job?->isActive(); $job?->isRunning(); $job?->isPaused(); $job?->isPreparing(); $job?->isFinished(); $job?->isFailed();
При локальном запуске облачные идентификаторы, например taskId и projectId, могут отсутствовать.
Состояния G-code
Состояние печати представлено enum GcodeState.
use Hopex\BambuLab\Gcode\Enum\GcodeState; $state = $client->state()->gcodeState(); if ($state === GcodeState::RUNNING) { echo 'Печать выполняется'; }
Вспомогательные методы:
$state?->isPrinting(); $state?->isPaused(); $state?->isFinished(); $state?->isFailed(); $state?->isIdle(); $state?->isPreparing();
Состояние FAILED может означать как реальную ошибку, так и ручную отмену задания.
Ожидание состояния
Ожидание запуска печати:
use Hopex\BambuLab\Gcode\Enum\GcodeState; $state = $client->waitForState( GcodeState::RUNNING, timeoutSeconds: 300, ); if ($state === null) { throw new RuntimeException( 'Принтер не начал печать.', ); }
Ожидание одного из нескольких состояний:
$state = $client->waitForState( states: [ GcodeState::PAUSE, GcodeState::FAILED, ], timeoutSeconds: 60, );
Ожидание пользовательского условия:
use Hopex\BambuLab\Printer\PrinterState; $reached = $client->waitUntil( condition: static fn(PrinterState $state): bool => ($state->progress() ?? 0) >= 50, timeoutSeconds: 3600, );
Управление печатью
Запуск задания
use Hopex\BambuLab\Printer\DTO\PrintJobOptions; $client->printer()->start( new PrintJobOptions( filename: 'model.3mf', plate: 1, useAms: false, amsMapping: [], bedLeveling: true, flowCalibration: false, vibrationCalibration: false, layerInspection: false, timelapse: false, ), );
Файл должен быть предварительно загружен на принтер.
Пауза
$client->printer()->pause();
Продолжение
$client->printer()->resume();
Остановка
$client->printer()->stop();
После ручной отмены принтер обычно сообщает состояние FAILED.
Запрос полного состояния
$client->printer()->requestFullState();
G-code
Отправка одной команды:
$client->gcode()->send('G28');
Отправка нескольких команд:
$client->gcode()->send( "G28\n" . "G1 Z10 F600\n", );
Произвольный G-code может запустить движение механизмов, нагрев и другие опасные операции. Проверяйте команды перед отправкой.
Подсветка
Включение:
$client->light()->turnOn();
Выключение:
$client->light()->turnOff();
Получение текущего состояния:
$light = $client->state()->lightState(); echo $light?->value ?? 'UNKNOWN';
Температура
Температура сопла:
$client->temperature()->setNozzle(220);
Температура стола:
$client->temperature()->setBed(60);
Получение текущих значений:
$status = $client->state()->status(); echo $status->nozzleTemperature; echo $status->nozzleTargetTemperature; echo $status->bedTemperature; echo $status->bedTargetTemperature; echo $status->chamberTemperature;
Настроенные ограничения SDK:
echo $client ->temperature() ->maximumNozzleTemperature(); echo $client ->temperature() ->maximumBedTemperature();
Корректная безопасная температура зависит от модели принтера, сопла, стола и используемого материала.
Вентиляторы
Управление вентиляторами выполняется через FanApi.
$client->fans()->setPart(128); $client->fans()->setAuxiliary(80); $client->fans()->setChamber(100);
Альтернативно можно использовать проценты.
$client->fans()->setPartPercent(50); $client->fans()->setAuxiliaryPercent(30); $client->fans()->setChamberPercent(40);
Остановка вентилятора:
$client->fans()->setPart(0);
Перед использованием дополнительного вентилятора рекомендуется проверить возможности принтера:
$capabilities = $client ->device() ->capabilities(); if ($capabilities->hasAuxiliaryFan() === true) { $client->fans()->setAuxiliaryPercent(50); }
При использовании заведомо отсутствующей возможности SDK может выбросить UnsupportedCapabilityException.
Файлы
Работа с файловой системой принтера выполняется через FTPS.
Типизированный список
foreach ($client->files()->entries() as $entry) { echo $entry->path; echo $entry->size; echo $entry->modifiedAt?->format('Y-m-d H:i:s'); }
Только файлы
foreach ($client->files()->files() as $file) { echo $file->name; }
Только директории
foreach ($client->files()->directories() as $directory) { echo $directory->name; }
Только модели 3MF
foreach ($client->files()->models() as $model) { echo $model->name; }
Фильтрация по расширению
$gcodeFiles = $client ->files() ->byExtension('gcode');
Можно передавать расширение с точкой или без неё:
$models = $client ->files() ->byExtension('.3mf');
Поиск элемента
$file = $client ->files() ->find('model.3mf'); if ($file !== null) { echo $file->size; }
Проверка существования
$exists = $client ->files() ->exists('model.3mf');
Пользовательская фильтрация
use Hopex\BambuLab\Files\DTO\FileEntry; $largeModels = $client->files()->filter( static fn(FileEntry $entry): bool => $entry->isFile() && $entry->hasExtension('3mf') && ($entry->size ?? 0) >= 500_000, );
Загрузка
$client->files()->upload( localPath: '/path/to/model.3mf', remotePath: 'model.3mf', );
Скачивание
$client->files()->download( remotePath: 'model.3mf', localPath: '/path/to/downloaded-model.3mf', );
Удаление
$client ->files() ->delete('model.3mf');
Файловые операции используют собственное FTPS-соединение и не зависят от активного MQTT-цикла.
Камера
Получение одного JPEG-кадра:
$frame = $client ->camera() ->snapshot();
Сохранение кадра:
$frame->saveAs( '/path/to/snapshot.jpg', );
Дополнительные представления:
echo $frame->mimeType(); echo $frame->base64(); echo $frame->dataUri(); echo $frame->bytes(); echo $frame->size(); echo $frame->isEmpty();
Поддержка камеры зависит от модели принтера и используемого локального протокола.
Текущая реализация TcpCameraTransport предназначена для совместимых локальных TLS-потоков камеры.
Информация об устройстве
$device = $client->device(); echo $device->host(); echo $device->serialNumber(); echo $device->wifiSignal(); echo $device->wifiSignalDbm(); echo $device->nozzleType(); echo $device->nozzleDiameter(); echo $device->lifecycle();
Состояние периферии:
$device->hasSdCard(); $device->hasAms(); $device->cameraAvailable(); $device->cameraRecordingEnabled(); $device->timelapseEnabled();
Возможности принтера
$capabilities = $client ->device() ->capabilities(); var_dump([ 'resolved' => $capabilities->isResolved(), 'camera' => $capabilities->hasCamera(), 'ams' => $capabilities->hasAms(), 'sd_card' => $capabilities->hasSdCard(), 'auxiliary_fan' => $capabilities->hasAuxiliaryFan(), 'chamber_fan' => $capabilities->hasChamberFan(), 'maximum_bed_temperature' => $capabilities->maximumBedTemperature(), 'maximum_nozzle_temperature' => $capabilities->maximumNozzleTemperature(), ]);
Возможности определяются по фактическому состоянию, полученному от принтера.
До полной синхронизации некоторые значения могут быть равны null.
Прошивка
Запрос актуальной информации:
$client->firmware()->refresh();
Получение основной версии:
echo $client ->firmware() ->current();
Получение модулей:
foreach ($client->firmware()->modules() as $module) { echo $module->name; echo $module->softwareVersion; echo $module->hardwareVersion; echo $module->serialNumber; echo $module->isOta(); }
Получение состояния обновления:
$upgrade = $client ->firmware() ->upgradeState(); if ($upgrade !== null) { echo $upgrade->status; echo $upgrade->progress; echo $upgrade->errorCode; }
Первая версия API прошивки предназначена только для чтения данных. Установка и откат прошивки не поддерживаются.
HMS
HMS содержит сообщения диагностики, предупреждения и аппаратные ошибки принтера.
foreach ($client->hms()->messages() as $message) { echo $message->identifier(); echo $message->level->value; echo $message->description; }
Предупреждения:
$warnings = $client ->hms() ->warnings();
Ошибки:
$errors = $client ->hms() ->errors();
Проверки:
$client->hms()->hasMessages(); $client->hms()->hasWarnings(); $client->hms()->hasErrors(); $client->hms()->hasUnknown();
Не все прошивки передают человекочитаемое описание и уровень сообщения. В таком случае SDK сохраняет исходные данные и использует уровень UNKNOWN.
События
Обработчики событий вызываются синхронно во время tick(), run() или runWithReconnect().
Начало печати
use Hopex\BambuLab\Events\PrinterStateSnapshot; $printStartedSubscription = $client->events()->onPrintStarted( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo 'Печать запущена'; }, ); $progressChangedSubscription = $client->events()->onProgressChanged( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo printf( "%d%%\n", $current->currentJob?->progress ?? 0, ); }, );
Пауза и продолжение
$client->events()->onPrintPaused( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo 'Печать приостановлена'; }, ); $client->events()->onPrintResumed( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo 'Печать продолжена'; }, );
Завершение и отмена
$client->events()->onPrintFinished( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo 'Печать завершена'; }, ); $client->events()->onPrintCancelled( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo 'Печать отменена'; }, );
Определение ручной отмены является эвристическим, поскольку принтер обычно использует состояние FAILED.
Изменение задания
$client->events()->onJobChanged( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo sprintf( '%s -> %s', $previous->currentJob?->fileName ?? 'NONE', $current->currentJob?->fileName ?? 'NONE', ); }, );
Изменение прогресса и слоя
$client->events()->onProgressChanged( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo $current->currentJob?->progress; }, ); $client->events()->onLayerChanged( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo sprintf( '%d/%d', $current->currentJob?->currentLayer ?? 0, $current->currentJob?->totalLayers ?? 0, ); }, );
Оставшееся время
$client->events()->onRemainingTimeChanged( static function ( PrinterStateSnapshot $current, PrinterStateSnapshot $previous, ): void { echo $current->currentJob?->remainingMinutes; }, );
Температура, свет и HMS
$client->events()->onTemperatureChanged(...); $client->events()->onLightChanged(...); $client->events()->onHmsChanged(...);
Отмена подписки
$subscription->cancel();
Удаление всех подписок:
$client->events()->clear();
Автоматическое переподключение
Для длительно работающих процессов можно использовать runWithReconnect().
use Hopex\BambuLab\Transport\ReconnectPolicy; $client->connect(); $client->runWithReconnect( new ReconnectPolicy( attempts: 10, delayMilliseconds: 3_000, subscriptionWarmupMilliseconds: 1_000, synchronizeAfterReconnect: true, clearStateBeforeReconnect: true, ), );
Параметры политики переподключения
| Параметр | Значение |
|---|---|
| attempts | количество попыток |
| delayMilliseconds | задержка между попытками |
| subscriptionWarmupMilliseconds | ожидание после подписки |
| synchronizeAfterReconnect | запрос полного состояния |
| clearStateBeforeReconnect | очистить накопленный PrinterState |
После успешного переподключения клиент:
- создаёт новое MQTT-соединение;
- повторно активирует подписку;
- запрашивает полное состояние;
- сохраняет зарегистрированные обработчики событий;
- продолжает цикл обработки сообщений.
Одна итерация с автоматическим восстановлением:
$client->tickWithReconnect( new ReconnectPolicy( attempts: 5, delayMilliseconds: 2_000, ), );
Явное переподключение:
$client->reconnect();
Пользовательские реализации
Основные механизмы SDK построены на контрактах.
MQTT-транспорт
use Hopex\BambuLab\Transport\Contracts\TransportContract;
Файловый транспорт
use Hopex\BambuLab\Files\Contracts\FileTransferContract;
Транспорт камеры
use Hopex\BambuLab\Camera\Contracts\CameraTransportContract;
Это позволяет заменить стандартную реализацию, например при интеграции с другим MQTT-клиентом, файловым шлюзом или собственным сервисом камеры.
Исключения
Все исключения SDK наследуются от:
Hopex\BambuLab\Exceptions\BambuException
Общая обработка:
use Hopex\BambuLab\Exceptions\BambuException; try { $client->connect(); } catch (BambuException $exception) { echo $exception->getMessage(); }
Основные группы исключений:
- ошибки подключения и транспорта;
- ошибки переподключения;
- ошибки сериализации MQTT;
- ошибки файловых операций;
- ошибки камеры;
- ошибки G-code;
- попытка использовать неподдерживаемую возможность.
Исключения разнесены по соответствующим feature-модулям.
Совместимость и ограничения
- SDK ориентирован на локальное управление принтером.
- Поведение протокола может отличаться между моделями и прошивками.
- Некоторые поля состояния могут отсутствовать.
- Не все функции протестированы на всех сериях Bambu Lab.
- AMS API пока не является приоритетным модулем.
- Потоковое видео камеры пока не поддерживается.
- Обновление и откат прошивки не поддерживаются.
- HMS может возвращать только код без текстового описания.
FAILEDне всегда означает аппаратную неисправность.- SDK не предоставляет облачную авторизацию Bambu Lab.
Документация
Полная документация по каждому модулю будет доступна отдельно:
Планируемые разделы:
- начало работы;
- клиент и подключение;
- состояние принтера;
- управление печатью;
- G-code;
- файлы;
- камера;
- температура;
- вентиляторы;
- подсветка;
- устройство;
- прошивка;
- HMS;
- события;
- переподключение;
- исключения;
- расширение SDK;
- архитектура.
Безопасность
Не публикуйте в репозитории:
- Access Code;
- серийный номер принтера;
- внутренний IP-адрес, если это нежелательно;
- файлы конфигурации с учётными данными.
Используйте переменные окружения:
$credentials = new PrinterCredentials( host: getenv('BAMBU_HOST'), accessCode: getenv('BAMBU_ACCESS_CODE'), serialNumber: getenv('BAMBU_SERIAL_NUMBER'), );
Не открывайте локальные сервисы принтера напрямую в интернет.
Статус проекта
SDK находится в активной разработке.
Перед выпуском стабильной версии рекомендуется зафиксировать:
- поддерживаемые модели;
- поддерживаемые версии PHP;
- список протестированных прошивок;
- правила обратной совместимости;
- формат версионирования.
Участие в разработке
Сообщения об ошибках и Pull Request приветствуются.
Перед отправкой изменений:
- проверьте соответствие структуры feature-first архитектуре;
- сохраняйте строгую типизацию;
- добавляйте документацию на русском языке;
- не добавляйте зависимость от Laravel в основной пакет;
- не ломайте существующие публичные контракты без необходимости.
Лицензия
Проект распространяется по лицензии MIT.