ESPHome PID Controller for Temperature using IR Remote Climate and HA Sensor

Hi,

Starting this thread to see if there are others out there trying to achieve similar things.

I need to control the temperature precisely using a heat pump that has an annoying logic for auto/temp control.

The idea is to use ESP Home PID controller and combine the following existing entities I have in Home Assistant.

I’m testing this in my office so the entities are all named office.

This is what gpt and I have got so far. Its doing funky shit like telling it to heat and cool at ther wrong time… dunno maybe I just need to dial it in.

remote_receiver:
  pin:
    number: GPIO32
    inverted: true
  dump: all

remote_transmitter:
  pin: GPIO26
  carrier_duty_percent: 50%

sensor:
  - platform: homeassistant
    id: esppoe_5_office_temperature
    name: "Office Temperature"
    entity_id: sensor.esppoe_5_office_temperature

globals:
  - id: last_mode_change
    type: int64_t
    restore_value: no
    initial_value: '0'
  - id: mode_change_delay
    type: int
    restore_value: no
    initial_value: '60000'  # 1 minute in milliseconds
  - id: last_mode
    type: int
    restore_value: yes
    initial_value: '0'  # 0 for OFF, 1 for COOL, 2 for HEAT
  - id: last_target_temp
    type: int
    restore_value: yes
    initial_value: '21'

output:
  - platform: template
    id: pid_output
    type: float
    write_action:
      - lambda: |-
          int64_t now = millis();
          int new_mode;
          int new_target_temp;
          climate::ClimateFanMode new_fan_mode;

          if (state > 0) {
            // Cooling needed
            new_mode = 1;
            new_target_temp = std::max(16, std::min(30, static_cast<int>(round(21 - state * 5))));
          } else {
            // Heating needed
            new_mode = 2;
            new_target_temp = std::max(16, std::min(30, static_cast<int>(round(21 - state * 5))));
          }

          if (std::abs(state) > 0.8f) new_fan_mode = climate::CLIMATE_FAN_HIGH;
          else if (std::abs(state) > 0.4f) new_fan_mode = climate::CLIMATE_FAN_MEDIUM;
          else new_fan_mode = climate::CLIMATE_FAN_LOW;

          bool change_needed = (new_mode != id(last_mode)) || 
                               (new_target_temp != id(last_target_temp)) ||
                               (new_fan_mode != id(office_ac).fan_mode);

          if (change_needed && (now - id(last_mode_change) > id(mode_change_delay))) {
            id(last_mode_change) = now;
            id(last_mode) = new_mode;
            id(last_target_temp) = new_target_temp;

            auto call = id(office_ac).make_call();
            call.set_mode(new_mode == 1 ? climate::CLIMATE_MODE_COOL : climate::CLIMATE_MODE_HEAT)
                .set_target_temperature(new_target_temp)
                .set_fan_mode(new_fan_mode)
                .perform();
            
            ESP_LOGD("PID", "Changed AC settings - Mode: %s, Temp: %d°C, Fan: %s", 
                     (new_mode == 1 ? "COOL" : "HEAT"), new_target_temp, 
                     (new_fan_mode == climate::CLIMATE_FAN_HIGH ? "HIGH" : 
                      new_fan_mode == climate::CLIMATE_FAN_MEDIUM ? "MEDIUM" : "LOW"));
          }

climate:
  - platform: pid
    id: pid_climate_controller
    name: "PID Climate Controller"
    sensor: esppoe_5_office_temperature
    default_target_temperature: 21°C
    cool_output: pid_output
    heat_output: pid_output
    control_parameters:
      kp: 0.5
      ki: 0.05
      kd: 0.1

  - platform: toshiba
    id: office_ac
    name: "Office AC"
    sensor: esppoe_5_office_temperature

button:
  - platform: template
    name: "PID Climate Autotune"
    on_press:
      - climate.pid.autotune: pid_climate_controller

Minisplit? There is no way you can win a war with them. Try to collaborate.
What’s the actual problem?

1 Like

Awesome thanks I’ll take a look

1 Like