Skip to content

Add Power/Jet fan speed (fan value 7) as CLIMATE_FAN_FOCUS - #188

Open
jkosharek wants to merge 1 commit into
JanM321:mainfrom
jkosharek:power-cool
Open

Add Power/Jet fan speed (fan value 7) as CLIMATE_FAN_FOCUS#188
jkosharek wants to merge 1 commit into
JanM321:mainfrom
jkosharek:power-cool

Conversation

@jkosharek

Copy link
Copy Markdown

…yte 3 bit 0x02

This adds support for the Power fan speed (Jet Cool / Jet Mode on LG remotes and ThinQ), which the protocol carries as fan speed 7 in the type 0 status message.

Verified on the wire (LG RAC_056905_WW wall unit): enabling Jet Cool from the ThinQ app makes the unit send C8.E3.40.00.00.04.03.66... - byte 1 = 0xE3 (fan bits = 7), byte 6 = 0x03 (the unit also self-drops the setpoint to 18C). Before this patch the controller logged received unexpected fan mode from AC (7), rejected the message, and as master then reverted the AC back to the previous fan speed within one status cycle.

Changes (all in lg-controller.h):

  • FAN_POWER added to LgCapability, gated on the capabilities message byte 3 bit 0x02 ("Supports fan speed Power")
  • Mapped to ESPHome's built-in CLIMATE_FAN_FOCUS (shows as "Focus" in HA), matching how other components expose turbo fan
  • Default and capability-override fan mode sets include it when supported
  • TX: CLIMATE_FAN_FOCUS -> fan bits 7; RX: fan value 7 -> CLIMATE_FAN_FOCUS

Tested: setting Focus from HA engages Power Cool on the unit (and the unit self-drops its setpoint to 18C, same as the app path); enabling Jet Cool from the ThinQ app is now tracked instead of rejected/reverted. Fan values 5/6 (low-medium / medium-high) are still unmapped - happy to add those too if you have a preferred mapping.


Bonus YAML for others (no code changes needed - sharing since it pairs well with this):

A ThinQ-style Power Cool on/off switch (saves the setpoint on turn-on, restores it on turn-off since the unit strands it at 18C). Requires a globals float pre_power_cool_target with restore_value: yes:

switch:
  - platform: template
    name: "Power Cool"
    lambda: |-
      return id(lg_ac_controller).fan_mode == climate::CLIMATE_FAN_FOCUS;
    turn_on_action:
      - lambda: |-
          if (id(lg_ac_controller).fan_mode != climate::CLIMATE_FAN_FOCUS) {
            id(pre_power_cool_target) = id(lg_ac_controller).target_temperature;
          }
      - climate.control:
          id: lg_ac_controller
          fan_mode: FOCUS
    turn_off_action:
      - lambda: |-
          auto call = id(lg_ac_controller).make_call();
          call.set_fan_mode(climate::CLIMATE_FAN_HIGH);
          call.set_target_temperature(id(pre_power_cool_target));
          call.perform();

And a smartthinq-style single "Vertical Swing" dropdown merging vane 1 position with the vertical sweep flag (for single-vane wall units; assumes the vane1 select has id: vane_position_1):

select:
  - platform: template
    name: "Swing - Vertical"
    update_interval: 15s
    options: ["Top", "MiddleTop1", "MiddleTop2", "MiddleBottom2", "MiddleBottom1", "Bottom", "Swing"]
    lambda: |-
      auto sw = id(lg_ac_controller).swing_mode;
      if (sw == climate::CLIMATE_SWING_VERTICAL || sw == climate::CLIMATE_SWING_BOTH)
        return std::string("Swing");
      auto v = id(vane_position_1).current_option();
      if (v == "1 (Up)")   return std::string("Top");
      if (v == "2")        return std::string("MiddleTop1");
      if (v == "3")        return std::string("MiddleTop2");
      if (v == "4")        return std::string("MiddleBottom2");
      if (v == "5")        return std::string("MiddleBottom1");
      if (v == "6 (Down)") return std::string("Bottom");
      return {};
    set_action:
      - lambda: |-
          bool horiz = (id(lg_ac_controller).swing_mode == climate::CLIMATE_SWING_HORIZONTAL ||
                        id(lg_ac_controller).swing_mode == climate::CLIMATE_SWING_BOTH);
          if (x == "Swing") {
            auto call = id(lg_ac_controller).make_call();
            call.set_swing_mode(horiz ? climate::CLIMATE_SWING_BOTH : climate::CLIMATE_SWING_VERTICAL);
            call.perform();
            return;
          }
          auto call = id(lg_ac_controller).make_call();
          call.set_swing_mode(horiz ? climate::CLIMATE_SWING_HORIZONTAL : climate::CLIMATE_SWING_OFF);
          call.perform();
          std::string opt;
          if (x == "Top")                opt = "1 (Up)";
          else if (x == "MiddleTop1")    opt = "2";
          else if (x == "MiddleTop2")    opt = "3";
          else if (x == "MiddleBottom2") opt = "4";
          else if (x == "MiddleBottom1") opt = "5";
          else if (x == "Bottom")        opt = "6 (Down)";
          auto vcall = id(vane_position_1).make_call();
          vcall.set_option(opt);
          vcall.perform();

(A matching "Swing - Horizontal" Off/Swing select is trivial the same way - the wired protocol only carries a horizontal sweep bit, no fixed horizontal positions.)

@apppie123

apppie123 commented Aug 16, 2026

Copy link
Copy Markdown

Great addition!

Thinking out loud: Do we know the protocol of the LG Thinq wifi module? Perhaps we can find some logic/similarities in the protocol to map the missing fan speeds.

protocol.md already contains the other fan speeds. I don't know where this is taken from, but my LG ignores 5 and 6.
Perhaps an extra bit needs to be set?

Fan speed
0: low
1: medium
2: high
3: auto
4: slow
5: low-medium
6: medium-high
7: power

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants