mirror of
https://github.com/esphome/esphome.git
synced 2024-11-26 17:05:21 +01:00
Base climate ir (#726)
* 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
This commit is contained in:
parent
1242f43769
commit
578e5a0d7a
6 changed files with 121 additions and 82 deletions
0
esphome/components/climate_ir/__init__.py
Normal file
0
esphome/components/climate_ir/__init__.py
Normal file
57
esphome/components/climate_ir/climate_ir.cpp
Normal file
57
esphome/components/climate_ir/climate_ir.cpp
Normal file
|
@ -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
esphome/components/climate_ir/climate_ir.h
Normal file
53
esphome/components/climate_ir/climate_ir.h
Normal file
|
@ -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
|
|
@ -3,7 +3,7 @@ import esphome.config_validation as cv
|
||||||
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
|
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
|
||||||
from esphome.const import CONF_ID, CONF_SENSOR
|
from esphome.const import CONF_ID, CONF_SENSOR
|
||||||
|
|
||||||
AUTO_LOAD = ['sensor']
|
AUTO_LOAD = ['sensor', 'climate_ir']
|
||||||
|
|
||||||
coolix_ns = cg.esphome_ns.namespace('coolix')
|
coolix_ns = cg.esphome_ns.namespace('coolix')
|
||||||
CoolixClimate = coolix_ns.class_('CoolixClimate', climate.Climate, cg.Component)
|
CoolixClimate = coolix_ns.class_('CoolixClimate', climate.Climate, cg.Component)
|
||||||
|
|
|
@ -27,8 +27,6 @@ const uint32_t COOLIX_FAN_MED = 0x5000;
|
||||||
const uint32_t COOLIX_FAN_MAX = 0x3000;
|
const uint32_t COOLIX_FAN_MAX = 0x3000;
|
||||||
|
|
||||||
// Temperature
|
// 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_TEMP_RANGE = COOLIX_TEMP_MAX - COOLIX_TEMP_MIN + 1;
|
||||||
const uint8_t COOLIX_FAN_TEMP_CODE = 0b1110; // Part of Fan Mode.
|
const uint8_t COOLIX_FAN_TEMP_CODE = 0b1110; // Part of Fan Mode.
|
||||||
const uint32_t COOLIX_TEMP_MASK = 0b11110000;
|
const uint32_t COOLIX_TEMP_MASK = 0b11110000;
|
||||||
|
@ -60,56 +58,7 @@ static const uint32_t FOOTER_SPACE_US = HEADER_SPACE_US;
|
||||||
|
|
||||||
const uint16_t COOLIX_BITS = 24;
|
const uint16_t COOLIX_BITS = 24;
|
||||||
|
|
||||||
climate::ClimateTraits CoolixClimate::traits() {
|
void CoolixClimate::transmit_state() {
|
||||||
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_() {
|
|
||||||
uint32_t remote_state;
|
uint32_t remote_state;
|
||||||
|
|
||||||
switch (this->mode) {
|
switch (this->mode) {
|
||||||
|
|
|
@ -1,43 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/components/climate_ir/climate_ir.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"
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace coolix {
|
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:
|
public:
|
||||||
void setup() override;
|
CoolixClimate() : climate::ClimateIR(COOLIX_TEMP_MIN, COOLIX_TEMP_MAX) {}
|
||||||
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:
|
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.
|
/// Transmit via IR the state of this climate controller.
|
||||||
void transmit_state_();
|
void transmit_state() override;
|
||||||
|
/// Handle received IR Buffer
|
||||||
bool on_receive(RemoteReceiveData data) override;
|
bool on_receive(remote_base::RemoteReceiveData data) override;
|
||||||
|
|
||||||
bool supports_cool_;
|
|
||||||
bool supports_heat_;
|
|
||||||
|
|
||||||
remote_transmitter::RemoteTransmitterComponent *transmitter_;
|
|
||||||
sensor::Sensor *sensor_{nullptr};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace coolix
|
} // namespace coolix
|
||||||
|
|
Loading…
Reference in a new issue