Actuating a Knob for PID Heater

Hi I’m trying to solicit some thoughts about a project I’ve been working on. I’m using esphome to try and automate a wall heater. The heater is controlled by a rotating knob. It can be set to off (0), or numbers 1 - 9, where 1 is barely on and 9 is cranking.

I made a meshing gear that sits on the knob and connects to a 28BYJ-48 stepper motor. The stepper is held in place by a bracket. I’m pretty comfortable using stepper in esphome–I use it with my blinds–but I haven’t created any heaters before in esphome.

It looks like I should be using pid climate, but it seems to want a heat_output pin. I tried creating a global float to hold the value, but I’m getting ID 'heater_output' of type globals::GlobalsComponent doesn't inherit from output::FloatOutput. Please double check your ID is pointing to the correct value.

Here’s where I am thus far:

substitutions:
  name: "heater"
  friendly_name: "Wall Heater"
  board: "esp32-c3-devkitm-1"

# board/wifi/ota stuff
packages:
  device_base: !include .esp32.yaml
  tmc_2209: !include 
    file: .2209.yaml
    vars:
      enable_pin: 2
      step_pin: 3
      dir_pin: 4
      dir_inverted: "True"
      diag_pin: 5
      pulley_diameter_mm: "21.963"
      gear_ratio: "1880/2000"
      distance_mm: "2050"
      acceleration: 500 steps/s^2
      velocity: 2500 steps/s # 200 (motor steps) * ${microsteps}
#      back_off_steps: "200" # back off some steps to reduce stepper energize noise
#      open_current_x: 1000ma
      open_stall_threshold_x: "28"
      close_current_x: 300ma
      close_stall_threshold_x: "30"
      tcool_threshold_x: "1000"
      tmc_address_x: "0x01"
      sense_resistor: "0.15 ohm"

globals:
   - id: heater_output
     type: float
     restore_value: no
     initial_value: '0'
      
sensor:
  - platform: internal_temperature
    name: "Internal Temperature"
    id: temperature_sensor

output:
  - platform: slow_pwm
    pin: 1
    id: heater
    period: 15s

# Example configuration entry
climate:
  - platform: pid
    name: "PID Climate Controller"
    sensor: temperature_sensor
    default_target_temperature: 21°C
    heat_output: heater_output
    control_parameters:
      kp: 0.49460
      ki: 0.00487
      kd: 12.56301
      output_averaging_samples: 5      # smooth the output over 5 samples
      derivative_averaging_samples: 5  # smooth the derivative value over 10 samples
    deadband_parameters:
      threshold_high: 0.5°C       # deadband within +/-0.5°C of target_temperature
      threshold_low: -0.5°C

Any guidance is greatly appreciated!

Looks like using a slow_pwm makes the pid heater happy, and I can use slow_pwms state_change_action with stepper.set_target. Think that should get it going

Can’t provide any guidance to your project but am trying to add similar knob to a water heater t-stat. Would love to see a picture of how you attached your stepper motor. Thanks

I had to scroll to the bottom of the pid page… What we need is:

sensor:
  - platform: pid
    name: "PID Climate Result"
    type: HEATER

Which outputs the result of the heat pin. The state_change_action I was trying to use before I think only responds to the momentary binary on/off value of the pwm pin, not the float value I had been trying to extract.

I modeled this meshing gear to sit on the knob…

The stepper insets into the hole you can see in the back.

1 Like

and with a little filtering and shaping, the sensor can set the stepper position directly:

# Assuming the sensor outputs a value between 0 and 1...
sensor:
  - platform: pid
    name: "PID Climate Heat"
    id: heat_float
    type: HEAT
    filters:
      - sliding_window_moving_average:
          window_size: 100
          send_every: 100
      - multiply: ${endstop}
      - round: 0
    on_value:
      then:
      - stepper.set_target:
          id: tmc_stepper
          target: !lambda return x;

I posted the model for the heater bracket and gear on printables.

And here is the working version of heater.yaml.

1 Like