Skip to content

Commit

Permalink
Base climate ir (esphome#726)
Browse files Browse the repository at this point in the history
* add ClimateIR

* update climate ir

* update class comment

* lint

* moved to climate_ir

* fix include path

* use climateir

* updates

* update include path

* lint

* fixed variable assigned to itself
  • Loading branch information
glmnet authored and OttoWinter committed Oct 17, 2019
1 parent 1242f43 commit 578e5a0
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 82 deletions.
Empty file.
57 changes: 57 additions & 0 deletions esphome/components/climate_ir/climate_ir.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "climate_ir.h"

namespace esphome {
namespace climate {

climate::ClimateTraits ClimateIR::traits() {
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(this->minimum_temperature_);
traits.set_visual_max_temperature(this->maximum_temperature_);
traits.set_visual_temperature_step(this->temperature_step_);
return traits;
}

void ClimateIR::setup() {
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_OFF;
// initialize target temperature to some value so that it's not NAN
this->target_temperature =
roundf(clamp(this->current_temperature, this->minimum_temperature_, this->maximum_temperature_));
}
// Never send nan to HA
if (isnan(this->target_temperature))
this->target_temperature = 24;
}

void ClimateIR::control(const climate::ClimateCall &call) {
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();
}

} // namespace climate
} // namespace esphome
53 changes: 53 additions & 0 deletions esphome/components/climate_ir/climate_ir.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include "esphome/components/climate/climate.h"
#include "esphome/components/remote_base/remote_base.h"
#include "esphome/components/remote_transmitter/remote_transmitter.h"
#include "esphome/components/sensor/sensor.h"

namespace esphome {
namespace climate {

/* A base for climate which works by sending (and receiving) IR codes
To send IR codes implement
void ClimateIR::transmit_state_()
Likewise to decode a IR into the AC state, implement
bool RemoteReceiverListener::on_receive(remote_base::RemoteReceiveData data) and return true
*/
class ClimateIR : public climate::Climate, public Component, public remote_base::RemoteReceiverListener {
public:
ClimateIR(float minimum_temperature, float maximum_temperature, float temperature_step = 1.0f) {
this->minimum_temperature_ = minimum_temperature;
this->maximum_temperature_ = maximum_temperature;
this->temperature_step_ = temperature_step;
}

void setup() override;
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; }

protected:
float minimum_temperature_, maximum_temperature_, temperature_step_;

/// Override control to change settings of the climate device.
void control(const climate::ClimateCall &call) override;
/// Return the traits of this controller.
climate::ClimateTraits traits() override;

/// Transmit via IR the state of this climate controller.
virtual void transmit_state() {}

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

remote_transmitter::RemoteTransmitterComponent *transmitter_;
sensor::Sensor *sensor_{nullptr};
};
} // namespace climate
} // namespace esphome
2 changes: 1 addition & 1 deletion esphome/components/coolix/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
from esphome.const import CONF_ID, CONF_SENSOR

AUTO_LOAD = ['sensor']
AUTO_LOAD = ['sensor', 'climate_ir']

coolix_ns = cg.esphome_ns.namespace('coolix')
CoolixClimate = coolix_ns.class_('CoolixClimate', climate.Climate, cg.Component)
Expand Down
53 changes: 1 addition & 52 deletions esphome/components/coolix/coolix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ const uint32_t COOLIX_FAN_MED = 0x5000;
const uint32_t COOLIX_FAN_MAX = 0x3000;

// Temperature
const uint8_t COOLIX_TEMP_MIN = 17; // Celsius
const uint8_t COOLIX_TEMP_MAX = 30; // Celsius
const uint8_t COOLIX_TEMP_RANGE = COOLIX_TEMP_MAX - COOLIX_TEMP_MIN + 1;
const uint8_t COOLIX_FAN_TEMP_CODE = 0b1110; // Part of Fan Mode.
const uint32_t COOLIX_TEMP_MASK = 0b11110000;
Expand Down Expand Up @@ -60,56 +58,7 @@ static const uint32_t FOOTER_SPACE_US = HEADER_SPACE_US;

const uint16_t COOLIX_BITS = 24;

climate::ClimateTraits CoolixClimate::traits() {
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(17);
traits.set_visual_max_temperature(30);
traits.set_visual_temperature_step(1);
return traits;
}

void CoolixClimate::setup() {
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_OFF;
// initialize target temperature to some value so that it's not NAN
this->target_temperature = (uint8_t) roundf(clamp(this->current_temperature, COOLIX_TEMP_MIN, COOLIX_TEMP_MAX));
}
// never send nan as temperature. HA will disable the user to change the temperature.
if (isnan(this->target_temperature))
this->target_temperature = 24;
}

void CoolixClimate::control(const climate::ClimateCall &call) {
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();
}

void CoolixClimate::transmit_state_() {
void CoolixClimate::transmit_state() {
uint32_t remote_state;

switch (this->mode) {
Expand Down
38 changes: 9 additions & 29 deletions esphome/components/coolix/coolix.h
Original file line number Diff line number Diff line change
@@ -1,43 +1,23 @@
#pragma once

#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/climate/climate.h"
#include "esphome/components/remote_base/remote_base.h"
#include "esphome/components/remote_transmitter/remote_transmitter.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/climate_ir/climate_ir.h"

namespace esphome {
namespace coolix {

using namespace remote_base;
// Temperature
const uint8_t COOLIX_TEMP_MIN = 17; // Celsius
const uint8_t COOLIX_TEMP_MAX = 30; // Celsius

class CoolixClimate : public climate::Climate, public Component, public RemoteReceiverListener {
class CoolixClimate : public climate::ClimateIR {
public:
void setup() override;
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; }
CoolixClimate() : climate::ClimateIR(COOLIX_TEMP_MIN, COOLIX_TEMP_MAX) {}

protected:
/// Override control to change settings of the climate device.
void control(const climate::ClimateCall &call) override;
/// Return the traits of this controller.
climate::ClimateTraits traits() override;

/// Transmit via IR the state of this climate controller.
void transmit_state_();

bool on_receive(RemoteReceiveData data) override;

bool supports_cool_;
bool supports_heat_;

remote_transmitter::RemoteTransmitterComponent *transmitter_;
sensor::Sensor *sensor_{nullptr};
void transmit_state() override;
/// Handle received IR Buffer
bool on_receive(remote_base::RemoteReceiveData data) override;
};

} // namespace coolix
Expand Down

0 comments on commit 578e5a0

Please sign in to comment.