Bambu Lab X1 X1C MQTT

Awesome! I’ve been considering doing some sort of mod with attaching an ESP powered from the printer - was hoping to make it multi function (bigger chamber light that toggles based on print stage/stage, possibly a NFC tag reader setup to auto configure AMS trays with non bambu spools etc) but was debating on how to power it.

Didn’t know about the open connectors on the printer’s PSU - was thinking of seeing if I could draw power from the empty plug on the AMS but that would work much better.

1 Like

This is awesome! I was just thinking about doing this, and then came across your post. I’m debating to control additional lighting separately from the fans and also if I should mount LED strips inside the chamber, or above the glass top. Or maybe just tie into the existing LED, but I haven’t done any exploring on what voltage it runs on.

I did come across a post talking about too much light possibly interfering with the LIDAR, so that’s possibly a consideration to have them automatically turn off during those steps as well. I haven’t checked to see if the factory LED goes off during that step, and if it does, if its status is updated thru MQTT.

Factory chamber light doesn’t change during the LIDAR steps, because it’s not bright enough by design to impact it too much. Though now that I think about it, if they have all this control onboard and knew the LIDAR detection could be a problem with a bright light, why not just have a brighter chamber light that auto dims during LIDAR stages, but bright during printing to be useable? Oh well, pretty niche idea to come up with - but definitely useful for us making external lights I guess.

1 Like

Does anyone know the mapping for some of the items?

{
    "print": {
        "ams_rfid_status": 0,  // ???
        "ams_status": 0,  // ???
        "bed_target_temper": 0.0,  // Target Bed Temp
        "bed_temper": 18.0,  // Current Bed Temp
        "big_fan1_speed": "0",  //Which Fan?
        "big_fan2_speed": "0",  // Which Fan?
        "chamber_temper": 25.0, // Chamber Temp
        "command": "push_status",  //Anyone got a translation list?
        "cooling_fan_speed": "0", // Assuming hot end fan?
        "fail_reason": "0", // Need mapping
        "fan_gear": 0, // Didn't know it had gears
        "force_upgrade": false, // ??
        "gcode_file": "/data/Metadata/plate_1.gcode", //Current GCode File for FTP
        "gcode_file_prepare_percent": "0", // Print Prep %
        "gcode_start_time": "1673459423", // Start timestamp
        "gcode_state": "FINISH", // Anyone have a list of states?
        "heatbreak_fan_speed": "15", // Not sure what this is, Mainboard?
        "hms": [ // Some Health issue codes ?
            {
                "attr": 50336000,
                "code": 131074
            },
            {
                "attr": 50335744,
                "code": 131074
            },
            {
                "attr": 201327360,
                "code": 196616
            }
        ],
        "home_flag": 328, // ???
        "hw_switch_state": 0, // ??
        "ipcam": {
            "ipcam_dev": "1", // ??
            "ipcam_record": "enable", // ??
            "resolution": "1080p", // Camera resolution
            "timelapse": "disable" // Timelapse Enabled
        },
        "lifecycle": "product", // ???
        "lights_report": [ // Light Statuses
            {
                "mode": "on",
                "node": "chamber_light"
            },
            {
                "mode": "flashing",
                "node": "work_light"
            }
        ],
        "mc_percent": 100, // Assume GCode % complete?
        "mc_print_error_code": "0",  // ??
        "mc_print_stage": "1", // ??
        "mc_print_sub_stage": 0, // ??
        "mc_remaining_time": 0, // Print time remaining?
        "mess_production_state": "active", // ???
        "nozzle_target_temper": 150.0, // Target Nozzle Temp
        "nozzle_temper": 143.0, // Current Nozzle Temp
        "online": {
            "ahb": false, // ??
            "rfid": false // ??
        },
        "print_error": 0, // ??
        "print_gcode_action": 255, // ??
        "print_real_action": 0, // ??
        "print_type": "cloud", // Assume LAN, SD or Cloud?
        "profile_id": "1143024", // ??
        "project_id": "1143026", // ?? 
        "sdcard": true, // Is there an SD Card inserted
        "sequence_id": "2021", // ??
        "spd_lvl": 2, // Assume silent is 1, ludicrous 4?
        "spd_mag": 100, // Speed %, normal = 100 etc
        "stg": [ // ??
            2,
            14,
            1
        ],
        "stg_cur": -1, // ??
        "subtask_id": "2200283", // ??
        "subtask_name": "Canister_plate_1", // Model name it's printing if multiple models in 1 file?
        "task_id": "2200282", // ??
        "upgrade_state": { // ???
            "ahb_new_version_number": "", 
            "ams_new_version_number": "",
            "consistency_request": false,
            "dis_state": 0,
            "err_code": 0,
            "force_upgrade": false,
            "message": "",
            "module": "null",
            "new_version_state": 2,
            "ota_new_version_number": "",
            "progress": "0",
            "sequence_id": 0,
            "status": "IDLE"
        },
        "upload": { // ??
            "file_size": 0,
            "finish_size": 0,
            "message": "Good",
            "oss_url": "",
            "progress": 0,
            "sequence_id": "0903",
            "speed": 0,
            "status": "idle",
            "task_id": "",
            "time_remaining": 0,
            "trouble_id": ""
        },
        "wifi_signal": "-37dBm", // Wifi Strength
        "xcam": { 
            "allow_skip_parts": false, // ??
            "buildplate_marker_detector": true, // Assume this is where it scans the Barcodes on the plates
            "first_layer_inspector": true, // As name
            "halt_print_sensitivity": "medium", // AI Sensititivty
            "print_halt": true, // Pause on error
            "printing_monitor": true, // AI monitoring
            "spaghetti_detector": true // Spaghetti section on
        },
        "xcam_status": "0" // ??
    }
}

Did someone succesfully connect with P1P? Trying ha-bambulab-devtest and mosquitto can’t connect to bambu broker.
image

Most of these I’ve got translated in the NR flow. But I’ll put what I know here. Also there are plenty of other weird data values from each AMS blurb I see you’re missing here. Do you also want that?

{
    "print": {
        "ams_rfid_status": 0,  // ??? - I assume when it's actively reading something but cannot confirm.
        "ams_status": 0,  // ???
        "bed_target_temper": 0.0,  // Target Bed Temp
        "bed_temper": 18.0,  // Current Bed Temp
        "big_fan1_speed": "0",  // Aux Fan
        "big_fan2_speed": "0",  // Chamber Fan
        "chamber_temper": 25.0, // Chamber Temp
        "command": "push_status",  // push_status is the main receive command. There are many other commands, some receive only, some work both ways.
        "cooling_fan_speed": "0", // Part Cooling Fan - on the magnetic cover of hotend but not hotend fan
        "fail_reason": "0", // ??? This is potentially documented on their wiki but I've never actually seen it last more than a few seconds with any status.
        "fan_gear": 0, // ???
        "force_upgrade": false, // ???
        "gcode_file": "/data/Metadata/plate_1.gcode", // Default name, even if it runs a different file this is the gcode_file. This is essentially useless and should look at the "sub_task" instead.
        "gcode_file_prepare_percent": "0", // Print Prep % - with how quick it is, this lasts only a few seconds. Essentially useless to monitor
        "gcode_start_time": "1673459423", // Start timestamp
        "gcode_state": "FINISH", // IDLE / RUNNING / FINISH / FAILED / PAUSE are all the ones I've seen/mapped
        "heatbreak_fan_speed": "15", // Hotend fan for the heatbreak.
        "hms": [ // HMS Status codes - wiki/slicer has more info on them but honestly feel like it isn't fully implemented yet.
            {
                "attr": 50336000,
                "code": 131074
            },
            {
                "attr": 50335744,
                "code": 131074
            },
            {
                "attr": 201327360,
                "code": 196616
            }
        ],
        "home_flag": 328, // ??? - Assuming the flag if the printer has been homed or not. Mine is 256 when I just turn on the printer. Not sure.
        "hw_switch_state": 0, // ??? - Thought it was the power on/off button, but that did not change it.
        "ipcam": {
            "ipcam_dev": "1", // ??
            "ipcam_record": "enable", // If recording of full video is enabled (not timelapse)
            "resolution": "1080p", // Camera resolution - 720p, 1080p.
            "timelapse": "disable" // Timelapse Enabled
        },
        "lifecycle": "product", // ??? - Probably left over from R&D, to identify if it's a testing unit or if it's made it off the shelf into product lifecycle.
        "lights_report": [ // Light Statuses
            {
                "mode": "on", // ON/OFF, toggleable
                "node": "chamber_light"
            },
            {
                "mode": "flashing", 
                "node": "work_light"
            }
        ],
        "mc_percent": 100, // Print progress percentage - includes progress from calibration and other steps
        "mc_print_error_code": "0",  // ?? - print specific error codes
        "mc_print_stage": "1", // ?? - print specific stage id's, not sure if any relation to action id's
        "mc_print_sub_stage": 0, // ?? - same thought as above?
        "mc_remaining_time": 0, // Print time remaining in minutes - is altered when speed profile changes :)
        "mess_production_state": "active", // ???
        "nozzle_target_temper": 150.0, // Target Nozzle Temp
        "nozzle_temper": 143.0, // Current Nozzle Temp
        "online": {
            "ahb": false, // ???
            "rfid": false // ???
        },
        "print_error": 0, // Error status codes, no mapping to them yet mostly because it sometimes clears
        "print_gcode_action": 255, // ???
        "print_real_action": 0, // ???
        "print_type": "cloud", // Assuming Cloud & LAN. SD is not a value. This only changes if you go into lan only mode as printing via sd card still has type cloud in lan mode off.
        "profile_id": "1143024", // Profile id from 3mf file for printjob
        "project_id": "1143026", // Project id from 3mf file for printjob
        "sdcard": true, // Is there an SD Card inserted
        "sequence_id": "2021", // The sequence ID of this status message
        "spd_lvl": 2, // 1/Silent, 2/Standard, 3/Sport, 4/Ludicrous
        "spd_mag": 100, // 50/Silent, 100/Standard, 124/Sport, 166%/Ludicrous
        "stg": [ // Previous stages of the printer, see Screenshot for mapping
            2,
            14,
            1
        ],
        "stg_cur": -1, // Current stage of printer, see Screenshot for mapping
        "subtask_id": "2200283", // ID of the printjob defined by 3mf file
        "subtask_name": "Canister_plate_1", // Model/3mf/job name. Closest you get to real gcode - I use this to fetch the print preview image from a FTP file download for example.
        "task_id": "2200282", // Print task id.
        "upgrade_state": { // ??? - I assume if there's a new version of firmware detected for download, these get filled.
            "ahb_new_version_number": "", 
            "ams_new_version_number": "",
            "consistency_request": false,
            "dis_state": 0,
            "err_code": 0,
            "force_upgrade": false,
            "message": "",
            "module": "null",
            "new_version_state": 2,
            "ota_new_version_number": "",
            "progress": "0",
            "sequence_id": 0,
            "status": "IDLE"
        },
        "upload": { // Progress when uploading a file to the printer, happens very fast then rests so not totally useful.
            "file_size": 0,
            "finish_size": 0,
            "message": "Good",
            "oss_url": "",
            "progress": 0,
            "sequence_id": "0903",
            "speed": 0,
            "status": "idle",
            "task_id": "",
            "time_remaining": 0,
            "trouble_id": ""
        },
        "wifi_signal": "-37dBm", // Wifi Strength
        "xcam": { 
            "allow_skip_parts": false, // ??? - I think this is an upcoming feature to skip failed parts in a multi-part print that some other slicers have, but bambu doesn't yet, judging by name.
            "buildplate_marker_detector": true, // Scans the Barcodes on the plates for assurance
            "first_layer_inspector": true, // As name
            "halt_print_sensitivity": "medium", // AI Sensititivty
            "print_halt": true, // Pause on error
            "printing_monitor": true, // AI monitoring
            "spaghetti_detector": true // Spaghetti section on
        },
        "xcam_status": "0" // ??? - Assumed this was lidar but didn't change so not sure.
    }
}

For the action id’s (stg array, stg_cur) this is the mapping we have for them, mostly taken from their wiki and snooping around. Ignore -2 Offline, I inject that in my flow.

Also all fan speeds are numbers from 1-15, and are translated to percentages via:
image

1 Like

P1P is very different for messages unfortunately - it isn’t powerful enough to mimic the MQTT broker of the X1C, and uses a minimal version to just output single messages on state changes. Most of the work here unfortunately won’t work for it except for translations/meanings of some values.

Connecting to it’s mqtt broker is another issue entirely. Even MQTT Explorer can’t connect to it (yet somehow NodeRed can according to a few people).

Soooo sad…

Thank you for your answear.

On the bright side, a few people are still trying! I would be too if I had the P1P. At the very least it looks like people will be able to get basic temperature data from it and maybe some more, though connecting to it may be a challenge at first.

Checked opened ports on P1P.

image

2 Likes

If anyone can get a copy of the MQTT data from it, then we can always try to see what it looks like.
Be interesting to see if the HA component im working on can stay connected

If you have the AMS stuff, that’d be great

I managed to sort out the direct MQTT connection now. Seems to be working pretty well. Unsure why some of the sensors are reporting as unavailable at the moment though, as the data is definitely there.

Might be unavailable if they haven’t changed in a while and have an expiry on them, but not sure.

I have a sample report here: Example MQTT Payload Report - Bambulab X1C - 2022-12-18 · GitHub it shows some of the AMS stuff. Note that humidity is the level there - actual value is reported under a different MQTT message that needs to be parsed out.

AMS’s are separated by an ID, starting at 0. And each AMS has trays with an ID, left to right 0,1,2,3. There is also a “tray_now” value which will be the number of the tray currently in use by the printer - and it’s based on AMS id and tray id, so tray_now 3 is ams 0 tray 3, tray_now 5 would be ams 1 tray 1 for example. When it’s equal to 255, then nothing is in use.

Each tray has values in it - vast majority are set only by the RFID of bambu spools which in this grab I didn’t have any loaded. So if you load them via the slicer, you basically only get nozzle temps, color, info_idx and tray_type.

FYI - Remain and tray_weight even with bambu spools are read only, and do not get changed with printing. At least not with the sample spools they gave in kickstarter shipments.

Tray_info_idx maps to the pre-selected profiles available in the slicer. I wrote a function in my nodered flow that takes these info_idx values and maps it to the human readable names, so use this as you will :slight_smile:

var PolyLite_PLA = {
    "tray_info_idx": "GFL00", 
    "tray_type": "PLA",
    "tray_sub_brands": "PolyLite PLA"
}

var PolyTerra_PLA = {
    "tray_info_idx": "GFL01",
    "tray_type": "PLA",
    "tray_sub_brands": "PolyTerra PLA"
}

var Bambu_ABS = {
    "tray_info_idx": "GFB00",
    "tray_type": "ABS"
}

var Bambu_PACF = {
    "tray_info_idx": "GFN03",
    "tray_type": "PC-CF"
}

var Bambu_PC = {
    "tray_info_idx": "GFC00",
    "tray_type": "PC"
}

var Bambu_PLA_Basic = {
    "tray_info_idx": "GFA00",
    "tray_type": "PLA",
    "tray_sub_brands": "PLA Basic"
}
var Bambu_PLA_Matte = {
    "tray_info_idx": "GFA01",
    "tray_type": "PLA",
    "tray_sub_brands": "PLA Matte"
}

var Support_G = {
    "tray_info_idx": "GFS01",
    "tray_type": "Support",
    "tray_sub_brands": "Support G"
}

var Support_W = {
    "tray_info_idx": "GFS00",
    "tray_type": "Support",
    "tray_sub_brands": "Support W"
}

var Bambu_TPU_95A = {
    "tray_info_idx": "GFU01",
    "tray_type": "TPU",
    "tray_sub_brands": "TPU 95A"
}

var Generic_ABS = {
    "tray_info_idx": "GFB99",
    "tray_type": "ABS",
    "tray_sub_brands": "ABS"
}

var Generic_ASA = {
    "tray_info_idx": "GFB98",
    "tray_type": "ASA",
    "tray_sub_brands": "ASA"
}

var Generic_PA = {
    "tray_info_idx": "GFN99",
    "tray_type": "PA",
    "tray_sub_brands": "PA"
}

var Generic_PACF = {
    "tray_info_idx": "GFN98",
    "tray_type": "PA-CF",
    "tray_sub_brands": "PA-CF"
}

var Generic_PC = {
    "tray_info_idx": "GFC99",
    "tray_type": "PC",
    "tray_sub_brands": "PC"
} 

var Generic_PETG = {
    "tray_info_idx": "GFG99",
    "tray_type": "PETG",
    "tray_sub_brands": "PETG"
}
var Generic_PLA = {
    "tray_info_idx": "GFL99",
    "tray_type": "PLA",
    "tray_sub_brands": "PLA"
}
var Generic_PLACF = {
    "tray_info_idx": "GFL98",
    "tray_type": "PLA-CF",
    "tray_sub_brands": "PLA-CF"
}
var Generic_PVA = {
    "tray_info_idx": "GFS99",
    "tray_type": "PVA",
    "tray_sub_brands": "PVA"
}
var Generic_TPU = {
    "tray_info_idx": "GFU99",
    "tray_type": "TPU",
    "tray_sub_brands": "TPU"
}

Amazing thanks.

The Unavailabile sensor is a bug somewhere with the HA integration and not with the MQTT message.

I really dont know why either. I can log out the variable and it returns in logs, so not sure why it’s not passing to HA at the moment

I have some free time this weekend, I think I’ll try to put in some functions for translations of certain values into your pybambu utils class file and put in a PR for stuff you’re currently missing.

That’s a weird bug, almost might suggest looking into a force-update interval for sensors when the mqtt is connected and all.

The Bento Box doesn’t do anything for noise except possibly add to it a little :slight_smile:

It’s a variation on the Nevermore recirculating air filter that is popular with Voron owners. When printing ABS or other filament that benefits from a higher, stable chamber temperature the recirculating filter keeps the warm air in, and the convection action helps (slightly) even out the chamber temp. You can hit 45c or so, and stay there, easily with it. Helps prevent warping and particularly for longer prints a higher stable chamber temp will add to ABS layer strength.

That’s only the secondary use for it though. It’s main purpose is to filter out VOC and gasses. It does a much better job than the X1C’s filter for a couple reasons: It’s multi-pass (i.e. it cleans the same air over and over) and as designed uses a first-stage HEPA filter to trap larger particles before the second-stage carbon pellets filter the rest.

Considering the X1C doesn’t even use the chamber fan/filter during ABS/etc. prints - because that would lower the chamber temp too much - this really helps clean things up. While the X1C by default will turn on the chamber fan full blast when an ABS/etc. print finishes, that is really not an optimal way to filter out gasses, etc. And you’ll get a lot of residue buildup inside the printer, particularly from ABS, that is a pain to clean and not great for your health.

Yeah it’s a lot simpler to tap the 24v power from the PSU. Just watch how much sustained draw you put on it. A couple fans, an ESP, and some LED lights won’t even pull an amp, which is well within the specs of the PSU, so just be mindful of what else you run off it.

I’d recommended putting a fuse inline on the main power tap with a quick fuse rated slightly higher than your expected draw - I have a 1amp fuse on mine.

This is exactly what can be done - I’m doing it :slight_smile:

In ESPHome I imported the “stage” entity from Home Assistant, the one your Flow provides in fact. Then just look for the “Printing” stage, which is only used for the actual print, not calibration. To turn the relay off look for the “Idle” stage.

I run my filter fans and LEDs off the same relay because both really only need to be on when actually printing.

Edit: I’m working on a full write-up on Github but in the short term if you are familiar with Home Assistant & ESPHome here’s the what the relevant bit of YAML looks like for all this:

text_sensor:
  - platform: homeassistant
    id: x1c_state
    entity_id: sensor.x1c_gt_x1c_stage
    on_value:
      then:
        - if:
            condition:
              lambda: 'return id(x1c_state).state == "Printing";'
            then:
              - switch.turn_on: relay1
        - if:
            condition:
              lambda: 'return id(x1c_state).state == "Idle";'
            then:
              - switch.turn_off: relay1

switch:
  - platform: gpio
    name: "BentoBox Fan Power"
    id: relay1
    pin: GPIO4
2 Likes

Target the mobile apps is my suggestion. I am also pretending to be a printer to the AWS Hosted MQTT which helps. If you can get the auth tokens still, you can do this. I’m unsure of the state of things with this at the moment. Someone getting in a flap about things for poor reasons means we have less visibility into the activity on our own networks now (gee thanks).

I’ve asked if they can properly support proxies, via Github and a support ticket.

How did you get report from P1P about nozzle and bed temps?

Edit: Connected to P1P only if no topics specified.

It’s my understanding that MQTT Explorer and the P1P don’t play nice for whatever reason, but if you connect with Node-Red and specify a topic, you can get the messages. I don’t have a P1P to play with, so I have no idea why and can’t dig in to it.