XY-ST30-W Temp Controller

I did a major rewrite of this code (see screen capture for a preview), but I’m still struggling to decipher the last two Sinilink Modbus addresses: 0x0014 (sleep switch) and 0x0015 (backlight grade). Neither seems to be doing anything, but I think the backlight address should be working. Does anyone have any ideas?

It’s still a work in progress, but I posted my work code to GitHub in case anyone is interested in testing it out or contributing. Thanks!

When I try to install Wirelessly in HA I get the following error
This is with latest version 1.4

INFO ESPHome 2026.1.5
INFO Reading configuration /config/esphome/xy-st30-w.yaml...
Failed config

select.template: [source /config/esphome/xy-st30-w.yaml:573]
  platform: template
  name: Filament Temp Preset
  optimistic: True
  options: 
    - Off
    - PLA
    - PETG
    - ABS
    - ASA
    - Nylon
    - User-defined
  initial_option: User-defined
  on_value: 
    - then: 
        - 
          Couldn't find ID 'filament_presets'. Please check you have defined an ID with that name in your configuration. These IDs look similar: "filament_temp_preset".
          lambda: !lambda |-
            if (x == "Off") {
              id(emergency_stop).turn_on();
              ESP_LOGI("preset", "Emergency stop activated");
              return;
            }
            
            if (x == "User-defined") {
              ESP_LOGI("preset", "User-defined mode selected");
              return;
            }
            
            // Look up the preset from the global map
            auto it = id(filament_presets).find(x);
            if (it != id(filament_presets).end()) {
              float temp_start = it->second.first;
              float temp_stop = it->second.second;
              
              auto call_start = id(temp_threshold_start).make_call();
              call_start.set_value(temp_start);
              call_start.perform();
              
              auto call_stop = id(temp_threshold_stop).make_call();
              call_stop.set_value(temp_stop);
              call_stop.perform();
              
              ESP_LOGI("preset", "%s mode set (%.1f°C - %.1f°C)",
                       x.c_str(), temp_start, temp_stop);
            } else {
              ESP_LOGW("preset", "Preset '%s' not found in filament_presets", x.c_str());
            }
  entity_category: config
  id: filament_temp_preset
  icon: mdi:thermometer-lines

@Rufan Filament_presets is defined in celsius.yaml or fahrenheit.yaml. For example: celsius.yaml:


globals:
  - id: filament_presets
    type: std::map<std::string, std::pair<float, float>>
    initial_value: |-
      []() {
        std::map<std::string, std::pair<float, float>> presets;
        presets[std::string("PLA")] = {${pla_temp} - 1, ${pla_temp} + 1};
        presets[std::string("PETG")] = {${petg_temp} - 1, ${petg_temp} + 1};
        presets[std::string("ABS")] = {${abs_temp} - 1, ${abs_temp} + 1};
        presets[std::string("ASA")] = {${asa_temp} - 1, ${asa_temp} + 1};
        presets[std::string("Nylon")] = {${nylon_temp} - 1, ${nylon_temp} + 1};
        return presets;
      }()

Depending on which package you include from temperature-controller.yaml:

packages:
  select_units: !include 
    # Select the appropriate temperature unit file to include based on your preference. 
    # Both files define the same entities, but with different units and value ranges.
    file: celsius.yaml
    #file: fahrenheit.yaml

Make sure you git clone the entire repo following the build instructions and not just download temperature-controller.yaml.

I feel so stupid, I just forgot to restart HA to reload the new celsius.yaml.
It is working now.
You did a very nice job building this, thanks for sharing

@Rufan Glad it’s working for you now. Thanks and appreciate the nice feedback!

It’s been working well for me over the past week, but if you have any usability suggestions, let me know.

Otherwise, beyond some documentation improvements and code commenting, I think it’s functionally done at this point.

1 Like

Sinilink makes very hackable devices. Great brand. ESPHome works super well with them.

@katherine

Running release [1.5.1] now.
I am wondering is it maybe an option to have a selection in HA on the Chamber Heater Controller Device page to select the: bambu_printer_entity_id.

Thanks

@Rufan, I don’t believe you can. AFAIK, when performing platform: homeassistant calls, the entity_id must be known at compile time. You cannot dynamically query Home Assistant to discover and set entity IDs at runtime.

The best you can do is secret substitutions like I have now. ESPHome is fairly limited in functionality, but it’s easy to develop applications such as this.

Also, you should upgrade to 1.5.3. Lots of code clean-up and optimizations, even though it’s only a point release. Hopefully, you figured out if you set the bambu_printer_id in secrets.yaml, the controller will automatically set the correct chamber heater temperature based on the filament type used during printing and turn it off when the print is done or canceled. It’s been working flawlessly for me.

I am positive you can get dynamic behavior working with Lambdas and the correct function calls.

@Rudd-O If you know a way to do this in a lambda, I’d be happy to implement it. I’m polling the printer status today using platform: homeassistant, but it requires a pre-defined (at compile time) entity_id:

  - platform: homeassistant
    name: "Bambu Printer Status"
    entity_id: sensor.${bambu_printer_entity_id}_print_status
    entity_category: diagnostic
    id: bambu_printer_status
    icon: "mdi:printer-3d"
    on_value:
      then:
        - lambda: |-
            if (x == "finish" || x == "failed" || x == "offline") {
              // Print ended - turn off chamber heater
              auto call = id(filament_temp_preset).make_call();
              call.set_option("Off");
              call.perform();
              ESP_LOGI("bambu", "Print ended, automatically turning off chamber heater");
            } else if (x == "running" || x == "prepare" || x == "slicing") {
              // Print started - auto-select chamber temp based on current filament
              ESP_LOGI("bambu", "Print started, auto-selecting chamber temperature");
            }
        - lambda: |-
            bool is_printing = (x == "running" || x == "prepare" || x == "slicing");
            if (is_printing) {
              id(auto_select_filament_preset)->execute();
            }

  - platform: homeassistant
    name: "Bambu Active Filament Type"
    entity_id: sensor.${bambu_printer_entity_id}_active_tray
    attribute: "type"
    entity_category: diagnostic
    id: bambu_filament_type
    on_value:
      then:
        - lambda: |-
            ESP_LOGI("bambu", "Active filament type changed to: %s", x.c_str());
        - lambda: |-
            // Only auto-select if printer is actively printing or preparing
            const auto& status = id(bambu_printer_status).state;
            bool is_printing = (status == "running" || status == "prepare" || status == "slicing");
            if (is_printing) {
              id(auto_select_filament_preset)->execute();
            }
    web_server:
      sorting_group_id: sorting_group_diagnostic

Unfortunately, I don’t know how to dynamically select/set the printer entity ID from Home Assistant in this context without also creating a template within Home Assistant itself.