Skip to content

Instantly share code, notes, and snippets.

@liads
Created June 16, 2019 20:53
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save liads/c702fd4b8529991af9cd52d03b694814 to your computer and use it in GitHub Desktop.
Save liads/c702fd4b8529991af9cd52d03b694814 to your computer and use it in GitHub Desktop.
ESPHome climate component for Electra AC (RC-3 IR remote)
#include "esphome.h"
static const char *TAG = "electra.climate";
typedef enum IRElectraMode {
IRElectraModeCool = 0b001,
IRElectraModeHeat = 0b010,
IRElectraModeAuto = 0b011,
IRElectraModeDry = 0b100,
IRElectraModeFan = 0b101,
IRElectraModeOff = 0b111
} IRElectraMode;
typedef enum IRElectraFan {
IRElectraFanLow = 0b00,
IRElectraFanMedium = 0b01,
IRElectraFanHigh = 0b10,
IRElectraFanAuto = 0b11
} IRElectraFan;
// That configuration has a total of 34 bits
// 33: Power bit, if this bit is ON, the A/C will toggle it's power.
// 32-30: Mode - Cool, heat etc.
// 29-28: Fan - Low, medium etc.
// 27-26: Zeros
// 25: Swing On/Off
// 24: iFeel On/Off
// 23: Zero
// 22-19: Temperature, where 15 is 0000, 30 is 1111
// 18: Sleep mode On/Off
// 17- 2: Zeros
// 1: One
// 0: Zero
typedef union ElectraCode {
uint64_t num;
struct {
uint64_t zeros1 : 1;
uint64_t ones1 : 1;
uint64_t zeros2 : 16;
uint64_t sleep : 1;
uint64_t temperature : 4;
uint64_t zeros3 : 1;
uint64_t ifeel : 1;
uint64_t swing : 1;
uint64_t zeros4 : 2;
uint64_t fan : 2;
uint64_t mode : 3;
uint64_t power : 1;
};
} ElectraCode;
const uint8_t ELECTRA_TEMP_MIN = 16; // Celsius
const uint8_t ELECTRA_TEMP_MAX = 30; // Celsius
#define ELECTRA_TIME_UNIT 1000
#define ELECTRA_NUM_BITS 34
class ElectraClimate : public climate::Climate, public Component {
public:
void setup() override
{
if (this->sensor_) {
this->sensor_->add_on_state_callback([this](float state) {
this->current_temperature = state;
// current temperature changed, publish state
this->publish_state();
});
this->current_temperature = this->sensor_->state;
} else
this->current_temperature = NAN;
// restore set points
auto restore = this->restore_state_();
if (restore.has_value()) {
restore->apply(this);
} else {
// restore from defaults
this->mode = climate::CLIMATE_MODE_AUTO;
// initialize target temperature to some value so that it's not NAN
this->target_temperature = roundf(this->current_temperature);
}
this->active_mode_ = this->mode;
}
void set_transmitter(remote_transmitter::RemoteTransmitterComponent *transmitter) {
this->transmitter_ = transmitter;
}
void set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
void set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
/// Override control to change settings of the climate device
void control(const climate::ClimateCall &call) override
{
if (call.get_mode().has_value())
this->mode = *call.get_mode();
if (call.get_target_temperature().has_value())
this->target_temperature = *call.get_target_temperature();
this->transmit_state_();
this->publish_state();
this->active_mode_ = this->mode;
}
/// Return the traits of this controller
climate::ClimateTraits traits() override
{
auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(this->sensor_ != nullptr);
traits.set_supports_auto_mode(true);
traits.set_supports_cool_mode(this->supports_cool_);
traits.set_supports_heat_mode(this->supports_heat_);
traits.set_supports_two_point_target_temperature(false);
traits.set_supports_away(false);
traits.set_visual_min_temperature(ELECTRA_TEMP_MIN);
traits.set_visual_max_temperature(ELECTRA_TEMP_MAX);
traits.set_visual_temperature_step(1);
return traits;
}
/// Transmit the state of this climate controller via IR
void transmit_state_()
{
ElectraCode code = { 0 };
code.ones1 = 1;
code.fan = IRElectraFan::IRElectraFanAuto;
switch (this->mode) {
case climate::CLIMATE_MODE_COOL:
code.mode = IRElectraMode::IRElectraModeCool;
code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
break;
case climate::CLIMATE_MODE_HEAT:
code.mode = IRElectraMode::IRElectraModeHeat;
code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
break;
case climate::CLIMATE_MODE_AUTO:
code.mode = IRElectraMode::IRElectraModeAuto;
code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
break;
case climate::CLIMATE_MODE_OFF:
default:
code.mode = IRElectraMode::IRElectraModeOff;
break;
}
auto temp = (uint8_t) roundf(clamp(this->target_temperature, ELECTRA_TEMP_MIN, ELECTRA_TEMP_MAX));
code.temperature = temp - 15;
ESP_LOGD(TAG, "Sending electra code: %lld", code.num);
auto transmit = this->transmitter_->transmit();
auto data = transmit.get_data();
data->set_carrier_frequency(38000);
uint16_t repeat = 3;
for (uint16_t r = 0; r < repeat; r++) {
// Header
data->mark(3 * ELECTRA_TIME_UNIT);
uint16_t next_value = 3 * ELECTRA_TIME_UNIT;
bool is_next_space = true;
// Data
for (int j = ELECTRA_NUM_BITS - 1; j>=0; j--)
{
uint8_t bit = (code.num >> j) & 1;
// if current index is SPACE
if (is_next_space) {
// one is one unit low, then one unit up
// since we're pointing at SPACE, we should increase it by a unit
// then add another MARK unit
if (bit == 1) {
data->space(next_value + ELECTRA_TIME_UNIT);
next_value = ELECTRA_TIME_UNIT;
is_next_space = false;
} else {
// we need a MARK unit, then SPACE unit
data->space(next_value);
data->mark(ELECTRA_TIME_UNIT);
next_value = ELECTRA_TIME_UNIT;
is_next_space = true;
}
} else {
// current index is MARK
// one is one unit low, then one unit up
if (bit == 1) {
data->mark(next_value);
data->space(ELECTRA_TIME_UNIT);
next_value = ELECTRA_TIME_UNIT;
is_next_space = false;
} else {
data->mark(next_value + ELECTRA_TIME_UNIT);
next_value = ELECTRA_TIME_UNIT;
is_next_space = true;
}
}
}
// Last value must be SPACE
data->space(next_value);
}
// Footer
data->mark(4 * ELECTRA_TIME_UNIT);
transmit.perform();
}
ClimateMode active_mode_;
bool supports_cool_{true};
bool supports_heat_{true};
remote_transmitter::RemoteTransmitterComponent *transmitter_;
sensor::Sensor *sensor_{nullptr};
};
@liads
Copy link
Author

liads commented Jun 16, 2019

Usage example in ESPHome yaml file:

climate:
  - platform: custom
    lambda: |-
      auto electra_climate = new ElectraClimate();
      electra_climate->set_sensor(id(my_temperature_sensor)); // Optional
      electra_climate->set_transmitter(id(my_ir_transmitter));
      App.register_component(electra_climate);
      return {electra_climate};

    climates:
      - name: "My Electra AC"

@thebne
Copy link

thebne commented Sep 11, 2021

2021 update: this is still working!
don't forget to add sensor: to your yaml file if you don't have that there already.

Thank you @liads

@mbrevda
Copy link

mbrevda commented Nov 14, 2022

Error on compile. Is there an updated version of this? Any way to get it integrated into esphome core?

@Arbel-arad
Copy link

i also get a compile error:
image
image

@Arbel-arad
Copy link

Arbel-arad commented Jan 3, 2023

so i went and fixed the errors:

#include "esphome.h"

static const char *TAG = "electra.climate";

typedef enum IRElectraMode {
    IRElectraModeCool = 0b001,
    IRElectraModeHeat = 0b010,
    IRElectraModeAuto = 0b011,
    IRElectraModeDry  = 0b100,
    IRElectraModeFan  = 0b101,
    IRElectraModeOff  = 0b111
} IRElectraMode;

typedef enum IRElectraFan {
    IRElectraFanLow    = 0b00,
    IRElectraFanMedium = 0b01,
    IRElectraFanHigh   = 0b10,
    IRElectraFanAuto   = 0b11
} IRElectraFan;

// That configuration has a total of 34 bits
//    33: Power bit, if this bit is ON, the A/C will toggle it's power.
// 32-30: Mode - Cool, heat etc.
// 29-28: Fan - Low, medium etc.
// 27-26: Zeros
//    25: Swing On/Off
//    24: iFeel On/Off
//    23: Zero
// 22-19: Temperature, where 15 is 0000, 30 is 1111
//    18: Sleep mode On/Off
// 17- 2: Zeros
//     1: One
//     0: Zero
typedef union ElectraCode {
    uint64_t num;
    struct {
        uint64_t zeros1 : 1;
        uint64_t ones1 : 1;
        uint64_t zeros2 : 16;
        uint64_t sleep : 1;
        uint64_t temperature : 4;
        uint64_t zeros3 : 1;
        uint64_t ifeel : 1;
        uint64_t swing : 1;
        uint64_t zeros4 : 2;
        uint64_t fan : 2;
        uint64_t mode : 3;
        uint64_t power : 1;
    };
} ElectraCode;

const uint8_t ELECTRA_TEMP_MIN = 16;  // Celsius
const uint8_t ELECTRA_TEMP_MAX = 30;  // Celsius
uint8_t target = 21;

#define ELECTRA_TIME_UNIT 1000
#define ELECTRA_NUM_BITS 34

class ElectraClimate : public climate::Climate, public Component {
 public:
  void setup() override
  {
    if (this->sensor_) {
      this->sensor_->add_on_state_callback([this](float state) {
        this->current_temperature = state;

        // current temperature changed, publish state
        this->publish_state();
      });
      this->current_temperature = this->sensor_->state;
    } else
      this->current_temperature = NAN;

    // restore set points
    auto restore = this->restore_state_();
    if (restore.has_value()) {
      restore->apply(this);
    } else {
      // restore from defaults
      this->mode = climate::CLIMATE_MODE_AUTO;

      // initialize target temperature to some value so that it's not NAN
      this->target_temperature = roundf(this->current_temperature);
    }

    this->active_mode_ = this->mode;
  }

  void set_transmitter(remote_transmitter::RemoteTransmitterComponent *transmitter) {
    this->transmitter_ = transmitter;
  }

  void set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
  void set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
  void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

  /// Override control to change settings of the climate device
  void control(const climate::ClimateCall &call) override
  {
    if (call.get_mode().has_value())
      this->mode = *call.get_mode();
    if (call.get_target_temperature().has_value())
      this->target_temperature = *call.get_target_temperature();

    this->transmit_state_();
    this->publish_state();

    this->active_mode_ = this->mode;
  }

  /// Return the traits of this controller
  climate::ClimateTraits traits() override
  {
    auto traits = climate::ClimateTraits();
    traits.set_supports_current_temperature(this->sensor_ != nullptr);
    traits.set_supports_auto_mode(true);
    traits.set_supports_cool_mode(this->supports_cool_);
    traits.set_supports_heat_mode(this->supports_heat_);
    traits.set_supports_two_point_target_temperature(false);
    traits.set_supports_away(false);
    traits.set_visual_min_temperature(ELECTRA_TEMP_MIN);
    traits.set_visual_max_temperature(ELECTRA_TEMP_MAX);
    traits.set_visual_temperature_step(1);
    return traits;
  }

  /// Transmit the state of this climate controller via IR
  void transmit_state_()
  {
    ElectraCode code = { 0 };
    code.ones1 = 1;
    code.fan = IRElectraFan::IRElectraFanAuto;

    switch (this->mode) {
      case climate::CLIMATE_MODE_COOL:
        code.mode = IRElectraMode::IRElectraModeCool;
        code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
        break;
      case climate::CLIMATE_MODE_HEAT:
        code.mode = IRElectraMode::IRElectraModeHeat;
        code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
        break;
      case climate::CLIMATE_MODE_AUTO:
        code.mode = IRElectraMode::IRElectraModeAuto;
        code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
        break;
      case climate::CLIMATE_MODE_OFF:
      default:
        code.mode = IRElectraMode::IRElectraModeOff;
        break;
    }
    target = (uint8_t) this->target_temperature;
    auto temp = (uint8_t) roundf(clamp(target, ELECTRA_TEMP_MIN, ELECTRA_TEMP_MAX));
    code.temperature = temp - 15;

    ESP_LOGD(TAG, "Sending electra code: %lld", code.num);

    auto transmit = this->transmitter_->transmit();
    auto data = transmit.get_data();

    data->set_carrier_frequency(38000);
    uint16_t repeat = 3;

    for (uint16_t r = 0; r < repeat; r++) {
      // Header
      data->mark(3 * ELECTRA_TIME_UNIT);
      uint16_t next_value = 3 * ELECTRA_TIME_UNIT;
      bool is_next_space = true;

      // Data
      for (int j = ELECTRA_NUM_BITS - 1; j>=0; j--)
      {
        uint8_t bit = (code.num >> j) & 1;

        // if current index is SPACE
        if (is_next_space) {
          // one is one unit low, then one unit up
          // since we're pointing at SPACE, we should increase it by a unit
          // then add another MARK unit
          if (bit == 1) {
            data->space(next_value + ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = false;

          } else {
            // we need a MARK unit, then SPACE unit
            data->space(next_value);
            data->mark(ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = true;
          }

        } else {
          // current index is MARK
          
          // one is one unit low, then one unit up
          if (bit == 1) {
            data->mark(next_value);
            data->space(ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = false;

          } else {
            data->mark(next_value + ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = true;
          }
        }
      }

      // Last value must be SPACE
      data->space(next_value);
    }

    // Footer
    data->mark(4 * ELECTRA_TIME_UNIT);

    transmit.perform();
  }

  ClimateMode active_mode_;

  bool supports_cool_{true};
  bool supports_heat_{true};

  remote_transmitter::RemoteTransmitterComponent *transmitter_;
  sensor::Sensor *sensor_{nullptr};
};

@mbrevda @

@schlumm
Copy link

schlumm commented Aug 6, 2023

I've tried to compile it but got the error message that
src\ElectraClimate.h: In member function 'virtual esphome::climate::ClimateTraits ElectraClimate::traits()':
src\ElectraClimate.h:116:39: warning: 'void esphome::climate::ClimateTraits::set_supports_auto_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
116 | traits.set_supports_auto_mode(true);

this error is for all the modes

the solution is to change the climate:

climate::ClimateTraits traits() override
{
  auto traits = climate::ClimateTraits();
  traits.set_supports_current_temperature(this->sensor_ != nullptr);
  traits.set_supported_modes({ climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_OFF });
  return traits;
}

@schlumm
Copy link

schlumm commented Aug 8, 2023

Can anyone knows how to add the support for the IR receiver, so a change with the regular remote will be reflected in HA?

@schlumm
Copy link

schlumm commented Aug 20, 2023

In order to add the support to the fan mode as well, need to have this file:

#include "esphome.h"

static const char *TAG = "electra.climate";

typedef enum IRElectraMode {
    IRElectraModeCool = 0b001,
    IRElectraModeHeat = 0b010,
    IRElectraModeAuto = 0b011,
    IRElectraModeDry  = 0b100,
    IRElectraModeFan  = 0b101,
    IRElectraModeOff  = 0b111
} IRElectraMode;

typedef enum IRElectraFan {
    IRElectraFanLow    = 0b00,
    IRElectraFanMedium = 0b01,
    IRElectraFanHigh   = 0b10,
    IRElectraFanAuto   = 0b11
} IRElectraFan;

// That configuration has a total of 34 bits
//    33: Power bit, if this bit is ON, the A/C will toggle it's power.
// 32-30: Mode - Cool, heat etc.
// 29-28: Fan - Low, medium etc.
// 27-26: Zeros
//    25: Swing On/Off
//    24: iFeel On/Off
//    23: Zero
// 22-19: Temperature, where 15 is 0000, 30 is 1111
//    18: Sleep mode On/Off
// 17- 2: Zeros
//     1: One
//     0: Zero
typedef union ElectraCode {
    uint64_t num;
    struct {
        uint64_t zeros1 : 1;
        uint64_t ones1 : 1;
        uint64_t zeros2 : 16;
        uint64_t sleep : 1;
        uint64_t temperature : 4;
        uint64_t zeros3 : 1;
        uint64_t ifeel : 1;
        uint64_t swing : 1;
        uint64_t zeros4 : 2;
        uint64_t fan : 2;
        uint64_t mode : 3;
        uint64_t power : 1;
    };
} ElectraCode;

const uint8_t ELECTRA_TEMP_MIN = 16;  // Celsius
const uint8_t ELECTRA_TEMP_MAX = 26;  // Celsius
uint8_t target = 21;

#define ELECTRA_TIME_UNIT 1000
#define ELECTRA_NUM_BITS 34

class ElectraClimate : public climate::Climate, public Component {
 public:
  void setup() override
  {
    if (this->sensor_) {
      this->sensor_->add_on_state_callback([this](float state) {
        this->current_temperature = state;

        // current temperature changed, publish state
        this->publish_state();
      });
      this->current_temperature = this->sensor_->state;
    } else
      this->current_temperature = NAN;

    // restore set points
    auto restore = this->restore_state_();
    if (restore.has_value()) {
      restore->apply(this);
    } else {
      // restore from defaults to be off (before was CLIMATE_MODE_AUTO
      this->mode = climate::CLIMATE_MODE_OFF;

      // initialize target temperature to some value so that it's not NAN
      this->target_temperature = roundf(this->current_temperature);
    }

    this->active_mode_ = this->mode;
  }

  void set_transmitter(remote_transmitter::RemoteTransmitterComponent *transmitter) {
    this->transmitter_ = transmitter;
  }

  void set_supported_cool(bool supported_cool) { this->supported_cool_ = supported_cool; }
  void set_supported_heat(bool supported_heat) { this->supported_heat_ = supported_heat; }
  void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

  /// Override control to change settings of the climate device
  void control(const climate::ClimateCall &call) override
  {
    if (call.get_mode().has_value())
      this->mode = *call.get_mode();
    if (call.get_target_temperature().has_value())
      this->target_temperature = *call.get_target_temperature();
//new
  if (call.get_fan_mode().has_value())
    this->fan_mode = *call.get_fan_mode();
// end new
    this->transmit_state_();
    this->publish_state();

    this->active_mode_ = this->mode;
  }

  /// Return the traits of this controller
/*   climate::ClimateTraits traits() override
  {
    auto traits = climate::ClimateTraits();
    traits.set_supports_current_temperature(this->sensor_ != nullptr);
    traits.set_supports_auto_mode(true);
    traits.set_supports_cool_mode(this->supports_cool_);
    traits.set_supports_heat_mode(this->supports_heat_);
    traits.set_supports_two_point_target_temperature(false);
    traits.set_supports_away(false);
    traits.set_visual_min_temperature(ELECTRA_TEMP_MIN);
    traits.set_visual_max_temperature(ELECTRA_TEMP_MAX);
    traits.set_visual_temperature_step(1);
    return traits;
  }
 */
climate::ClimateTraits traits() override
{
  auto traits = climate::ClimateTraits();
  traits.set_supports_current_temperature(this->sensor_ != nullptr);
  traits.set_supported_modes({ climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_OFF });
  
// added the below line for having support for the fans modes as from climate_traits.h
  traits.set_supported_fan_modes({ climate::CLIMATE_FAN_ON, climate::CLIMATE_FAN_OFF, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH });

  traits.set_supports_two_point_target_temperature(false);
  //traits.set_supports_away(false);
  traits.set_visual_min_temperature(ELECTRA_TEMP_MIN);
  traits.set_visual_max_temperature(ELECTRA_TEMP_MAX);
  traits.set_visual_temperature_step(1);
  return traits;
}

  /// Transmit the state of this climate controller via IR
  void transmit_state_()
  {
    ElectraCode code = { 0 };
    code.ones1 = 1;
// original before the switch    code.fan = IRElectraFan::IRElectraFanAuto;
	
/// below is for adding the fan mode
    switch (this->fan_mode.value()) {
      case climate::CLIMATE_FAN_LOW:
        code.fan = IRElectraFan::IRElectraFanLow;
        break;
      case climate::CLIMATE_FAN_MEDIUM:
        code.fan = IRElectraFan::IRElectraFanMedium;
        break;
      case climate::CLIMATE_FAN_HIGH:
        code.fan = IRElectraFan::IRElectraFanHigh;
        break;
      case climate::CLIMATE_FAN_ON:
      default:
        code.fan = IRElectraFan::IRElectraFanLow;// original IRElectraFanAuto
        break;
    }
/// above is for adding the fan mode

    switch (this->mode) {
      case climate::CLIMATE_MODE_COOL:
        code.mode = IRElectraMode::IRElectraModeCool;
        code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
        break;
      case climate::CLIMATE_MODE_HEAT:
        code.mode = IRElectraMode::IRElectraModeHeat;
        code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
        break;
      case climate::CLIMATE_MODE_AUTO:
        code.mode = IRElectraMode::IRElectraModeAuto;
        code.power = this->active_mode_ == climate::CLIMATE_MODE_OFF ? 1 : 0;
        break;
      case climate::CLIMATE_MODE_OFF:
      default:
        code.mode = IRElectraMode::IRElectraModeOff;
        break;
    }
    target = (uint8_t) this->target_temperature;
    auto temp = (uint8_t) roundf(clamp(target, ELECTRA_TEMP_MIN, ELECTRA_TEMP_MAX));
    code.temperature = temp - 15;

    ESP_LOGD(TAG, "Sending electra code: %lld", code.num);

    auto transmit = this->transmitter_->transmit();
    auto data = transmit.get_data();

    data->set_carrier_frequency(38000);
    uint16_t repeat = 3;

    for (uint16_t r = 0; r < repeat; r++) {
      // Header
      data->mark(3 * ELECTRA_TIME_UNIT);
      uint16_t next_value = 3 * ELECTRA_TIME_UNIT;
      bool is_next_space = true;

      // Data
      for (int j = ELECTRA_NUM_BITS - 1; j>=0; j--)
      {
        uint8_t bit = (code.num >> j) & 1;

        // if current index is SPACE
        if (is_next_space) {
          // one is one unit low, then one unit up
          // since we're pointing at SPACE, we should increase it by a unit
          // then add another MARK unit
          if (bit == 1) {
            data->space(next_value + ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = false;

          } else {
            // we need a MARK unit, then SPACE unit
            data->space(next_value);
            data->mark(ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = true;
          }

        } else {
          // current index is MARK
          
          // one is one unit low, then one unit up
          if (bit == 1) {
            data->mark(next_value);
            data->space(ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = false;

          } else {
            data->mark(next_value + ELECTRA_TIME_UNIT);
            next_value = ELECTRA_TIME_UNIT;
            is_next_space = true;
          }
        }
      }

      // Last value must be SPACE
      data->space(next_value);
    }

    // Footer
    data->mark(4 * ELECTRA_TIME_UNIT);

    transmit.perform();
  }

/* these are new rows for getting the IR reciever data - original from coolix.h
  /// Handle received IR Buffer
  static bool on_electra(climate::Climate *parent, remote_base::RemoteReceiveData data);
  bool on_receive(remote_base::RemoteReceiveData data) override { return ElectraClimate::on_electra(this, data); }

///original 
///  bool on_receive(remote_base::RemoteReceiveData data) override { return CoolixClimate::on_coolix(this, data); }

 */


  ClimateMode active_mode_;

  bool supported_cool_{true};
  bool supported_heat_{true};

  remote_transmitter::RemoteTransmitterComponent *transmitter_;
  sensor::Sensor *sensor_{nullptr};
};

@addadi
Copy link

addadi commented Jan 25, 2024

can anyone share example of full yaml file? thanks

@schlumm
Copy link

schlumm commented Feb 7, 2024

I used esp8266-01, so the pins are for this chip.

captive_portal:
sensor:
  - platform: dht
    model: DHT22
    pin: 0
    id: dht_sensor
    temperature:
      name: "AC Parents Temperature"
      id: dht_temp
    humidity:
      name: "AC Parents Humidity"
    update_interval: 60s  

remote_transmitter:
  pin: 3  #RX pin
  carrier_duty_percent: 50%
  id: my_ir_transmitter

remote_receiver:
  pin: 
    number: 1 #TX pin
    inverted: True
    mode: INPUT_PULLUP
  id: ir_receiver
  dump: raw
  tolerance: 55%
 
climate:
  - platform: custom
    lambda: |-
      auto electra_climate = new ElectraClimate();
      electra_climate->set_sensor(id(dht_temp)); // Optional
      electra_climate->set_transmitter(id(my_ir_transmitter));
      App.register_component(electra_climate);
      return {electra_climate};

    climates:
      - name: "Parents AC"
        id: climate_id

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