Bambu Lab X1 X1C MQTT

That’s fine. The logic remains the same whether or not its a Bridged connection within HA, or a direct connection to the broker on the printer.

I’ve already begun parsing this data as you can see in the screenshot above

I’m still unable to get my Mosquitto instance to show the brokered connection. No idea why it’s stopped working :frowning:

You can filter without issue in HA natively, I’m still doing it the MQTT way from what I posted way back on Discord and it’s filtered and doesn’t clutter my logs at all. I think ultimately there are many ways to do this, so one size won’t fit all :smiley:

It’s horrible (imo) but it’s worked for months for me, so I’ve not changed it (been busy with other HA things). As a result, it needs fixes, tidy ups etc. but you can see how I tackled the filtering back then.

    - name: "X1C AMS Temperature"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_ams_0_temp"
      unit_of_measurement: "°C"
      value_template: >
        {% if value_json.print is defined and value_json.print.ams is defined %}
          {{ value_json.print.ams.ams[0].temp }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C AMS Humidity"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_ams_0_humidity"
      unit_of_measurement: "%"
      value_template: >
        {% if value_json.print is defined and value_json.print.ams is defined %}
          {{ value_json.print.ams.ams[0].humidity }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Bed Temperature Target"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_bed_target_temper"
      unit_of_measurement: "°C"
      value_template: >
        {% if value_json.print is defined and value_json.print.bed_target_temper is defined %}
          {{ value_json.print.bed_target_temper }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Bed Temperature"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_bed_temper"
      unit_of_measurement: "°C"
      value_template: >
        {% if value_json.print is defined and value_json.print.bed_temper is defined %}
          {{ value_json.print.bed_temper }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Chamber Temperature"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_chamber_temper"
      unit_of_measurement: "°C"
      value_template: >
        {% if value_json.print is defined and value_json.print.chamber_temper is defined %}
          {{ value_json.print.chamber_temper }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Part Cooling Fan Speed"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_cooling_fan_speed"
      unit_of_measurement: "%"
      value_template: >
        {% if value_json.print is defined and value_json.print.cooling_fan_speed is defined %}
          {{ value_json.print.cooling_fan_speed | int(base=16)*100/16 }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Cooling Fan Speed"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_heatbreak_fan_speed"
      unit_of_measurement: "%"
      value_template: >
        {% if value_json.print is defined and value_json.print.heatbreak_fan_speed is defined %}
          {{ value_json.print.heatbreak_fan_speed }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Nozzle Temperature Target"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_nozzle_target_temper"
      unit_of_measurement: "°C"
      value_template: >
        {% if value_json.print is defined and value_json.print.nozzle_target_temper is defined %}
          {{ value_json.print.nozzle_target_temper }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Nozzle Temperature"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_nozzle_temper"
      unit_of_measurement: "°C"
      value_template: >
        {% if value_json.print is defined and value_json.print.nozzle_temper is defined %}
          {{ value_json.print.nozzle_temper }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Aux Cooling Fan Speed"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_big_fan1_speed"
      unit_of_measurement: "%"
      value_template: >
        {% if value_json.print is defined and value_json.print.big_fan1_speed is defined %}
          {{ value_json.print.big_fan1_speed }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Big Fan2 Speed"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_big_fan2_speed"
      unit_of_measurement: "%"
      value_template: >
        {% if value_json.print is defined and value_json.print.big_fan2_speed is defined %}
          {{ value_json.print.big_fan2_speed }}"
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Print Status"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_gcode_state"
      value_template: >
        {% if value_json.print is defined and value_json.print.gcode_state is defined %}
          {{ value_json.print.gcode_state | capitalize }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Print Progress"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_mc_percent"
      unit_of_measurement: "%"
      value_template: >
        {% if value_json.print is defined and value_json.print.mc_percent is defined %}
          {{ value_json.print.mc_percent }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
    - name: "X1C Print Time Remaining"
      state_topic: "device/00M00A123456789/report"
      unique_id: "00M00A123456789_mc_remaining_time"
      unit_of_measurement: "min"
      value_template: >
        {% if value_json.print is defined and value_json.print.mc_remaining_time is defined %}
          {{ value_json.print.mc_remaining_time }}
        {% else %}
          {{ states(entity_id) }}
        {% endif %}
1 Like

If it works, it works! Who knows what outdated stuff I have in my HA that could be done much easier but it just “works” (SNMP sensors for my UPS’s, weird shell scripts that go through 3 devices just to do WoL, a few web scrapers for sensor data…).

Doing a bit more digging into what other mqtt messages might be useful, and just discovered one I’d love to have but it’s very selective when it’s sent - Getting firmware version of the printer and AMS is sent in a payload.info with command “get_version” at the start of a print.

I’m not extremely familiar with MQTT still but I’m wondering if this read-only command and others like it can just be sent to the printer’s broker to receive the information - like how we had commands to setting AMS filament tray values or toggling the light and speed profile. Going to look into this as I can augment the HA device’s info with the native version info.

Oh my that was way easier than I expected.

Sending a payload of this
{ "info": { "sequence_id": "20004", "command": "get_version" }, "user_id": "1234567890" }
Will report the version of everything. Going to integrate this into my NR flow and update it later!

1 Like

@WolfwithSword do you know if there’s a command to get the ActionID in the same manner?

I’m wondering if I can just query the X1’s MQTT server via payload and get the value of the ActionID (i.e. “0” (which = Printing) “1” (= auto bed leveling) and so on.

I’d love to be able to use my ESP8266 to get the state directly without having to go through Home Assistant/etc. I have the latter working fine and am using the state to trigger a relay on my ESP device to turn a recirculating fan and auxiliary led lights on if printing has started (and off when it stops) but the ESP isn’t powerful enough to parse the constantly updating json stream from the mqtt feed. However if I can send a msg instead with a payload that returns the state it could work, then I wouldn’t need HA for this part (though I’d still use the NR integration here for other information).

I’m not sure, one would have to do a lot of snooping of messages to view these and look for a command, and try to find useful data. Likely the action id’s might also be in a mc_print message with some command and sequence id, then would need to be parsed, but I wouldn’t know which. Best way to snoop that is to save and store all messages (or just mc_print if you feel lucky with it) during the phases of a print and hope you find one. It should give you the sequence id and command name needed.

One thing I was hoping to snoop/find is a command to get the amount of filament used when a print ends, or something like that.

1 Like

Updated the NR flow & the HomeAssistant YAML as I also fixed an issue with the speed control & speed select/sensor setup.

Speed Select is actually fully working properly, I had mixed up sensor/select topics which caused some issues. I also added Speed Info which is just the same data, but since Select’s can’t show attributes, the speed_info will.

Added the SerialNumber, HW_Version and SW_Version for the printer and all attached AMS units as sensors (removed machine_serial from printer) and also natively to the HA device data. This will try to fetch on a 1 minute interval in NodeRed if the printer is connected.

Should be there for you.

    "mc_print": {
        "command": "push_info",
        "param": "[AMS][Period]:len=1.610m,buf_pos=0.22,e_hall=350mV,cut_hall=1601mV",
        "sequence_id": "2943"
    }
}

This however does count the feed in through the AMS at the start. I’m sure you could do something to get the number before the print properly starts and then again at the end and take the difference?

Ah, so it can report length of filament, interesting.

I was hoping there would be one for grams (though not always exact, conversion from length to weight can be averaged and be still a good estimate), and seeing that is reported via AMS, then the odd print without the AMS wouldn’t get counted. I think I might resort to just scanning the 3mf file for approx weight, since I know it gets reported after each print.

Then again that might just be the total max estimated weight, so in case of failures/cancelling, may need to factor in the print progress % (unless it already does that when it reports it on the screen, but I don’t think that value is sent anywhere so unlikely).

Edit: Looks like I’ll have to extract from the gcode/3mf then in my FTP fetch flow. Monitoring the mqtt messages starting a print from SD card, and I saw one message/command that looked promising but doesn’t include that type of info.

payload: {
    print: {
      command: 'project_file',
      param: 'Metadata/plate_1.gcode',
      reason: 'SUCCESS',
      result: 'SUCCESS',
      sequence_id: '149',
      subtask_name: 'the_file_name.gcode.3mf',
    }
  }

Managed to get the integration working without the requirement of an MQTT Bridge :partying_face:

Struggling through how best to setup a hacs repo that can be easily cloned and worked on, without the need to manually add stuff to HA etc

2 Likes

What would still need to be manually added to HA if you solved the MQTT connect issue?

If you mean to continue development while it’s an active hacs repo, I’d suggest to follow some of the custom component dev environment docs to setup the dev container for editing and loading in a standalone HA instance. It’s what I had running until the MQTT issues cropped up.

Nothing. Right now, you put the IP of the printer in and away you go.

It’s the custom component Dev environments I need to figure out. Not really sure where to get started with that - Dev containers are relatively new to me

OK, got a HACS repo (i think) up. It’s still very very much a WIP, but its a solid start I think: GitHub - greghesp/ha-bambulab

3 Likes

Thought I’d share my little project that leverages MQTT:

Wemos D1 Mini (esp8266, you can get these on Amazon, AliExpress, and a billion other places)
24v 1-channel opto relay
Buck converter (MP1584EN)
And various cable bits & ends. All told about $15 in parts give or take.

I’ll do a write up for a Gist for the yaml code and wiring diagram but it is pretty straightforward - I use ESPHome with Home Assistant which makes programming these things a snap.

When the device sends a status of “Printing” it flips the relay and turns on power to my recirculating air filter (The Bambu BentoBox). When the print is finished and “Idle” is sent it turns it off. I plan on wiring some auxillary LED lights to this as well to accomplish the same thing.

Power for the entire thing comes from a 24v tap of the X1C’s power supply - it has two free spots you can attach to with fork connectors. The bucky drops the voltage to 5v for the ESP; my fans are already 24v (as will be the lights). It’s entirely self contained - I whipped up a very simple mount for the components (see pic) and attached it via double sided tape to an open spot behind the power plug - it’s obvious when you remove the back cover where it should go.

No problems with the wifi signal on the ESP being inside the enclosure and all components can operate at temp ranges far above anything the chamber can produce so no worries there either.

Thought I’d share since I’m importing a sensor from Home Assistant made possible by all the work others have done here - thanks! Ultimately I’d love to run this all on the ESP device itself - it has an MQTT client - but currently the way Bambu has MQTT implemented makes that impossible, or at least I haven’t found a way around it. ESP devices aren’t very powerful/don’t have much memory and the json string overwhelmed it in my tests.

3 Likes

You’re braver than me. I’ve done the same, but just used a smart plug :joy:

I agree, the MQTT implementation is… pretty terrible. don’t understand why it’s lumped in 1 big JSON object rather than topics.

I did some network sniffing of traffic, and it seems the cloud service for the app is also MQTT. Haven’t been able to get any data though to see if it’s the same. Seems to come through us.mqtt.bambulab.com

Out of interest, how did you manage to decrypt this? I’m unable to get the content to load because it’s all secure traffic, but the certificate for my mitm gets rejected

I considered the smart plug route - I already use one for the printer itself - but that would have required running cables outside the enclosure for the BentoBox.

I’m going to insert a 1a quick fuse inline with the power tap to guard against possible problems, such as my mounted board falling off and coming in to contact with the plug. The risk is low, but low risk /= no risk as the saying goes.

Ahh yes, for some reason I thought you’d find this for the 240v printer power :joy:

Does the Bento box actually help noise without affecting temps?

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.