add support for climate action (#720)

* add support for climate action:

Following hass implementation of climate, action represents the current action the climate device is perfoming, e.g. cooling or heating

fix bang_bang climate:

make sure that the thresholds are always respected.
fixes the issue where the component would just keep on heating, regardless of the temperature range

* Updates

- Use dedicated enum for action (otherwise it gets confusing because "auto" is not a valid action)
- Add field to tell HA that action is supported
- Revert semantic changes in bang_bang

* Conditional print


Co-authored-by: Otto Winter <otto@otto-winter.com>
This commit is contained in:
Marcel van der Veldt
2019-10-18 10:39:14 +02:00
committed by Otto Winter
parent 22aecdfc6f
commit 72d6471ab8
12 changed files with 101 additions and 25 deletions
@@ -46,52 +46,51 @@ climate::ClimateTraits BangBangClimate::traits() {
traits.set_supports_heat_mode(this->supports_heat_);
traits.set_supports_two_point_target_temperature(true);
traits.set_supports_away(this->supports_away_);
traits.set_supports_action(true);
return traits;
}
void BangBangClimate::compute_state_() {
if (this->mode != climate::CLIMATE_MODE_AUTO) {
// in non-auto mode
this->switch_to_mode_(this->mode);
this->switch_to_action_(static_cast<climate::ClimateAction>(this->mode));
return;
}
// auto mode, compute target mode
if (isnan(this->current_temperature) || isnan(this->target_temperature_low) || isnan(this->target_temperature_high)) {
// if any control values are nan, go to OFF (idle) mode
this->switch_to_mode_(climate::CLIMATE_MODE_OFF);
this->switch_to_action_(climate::CLIMATE_ACTION_OFF);
return;
}
const bool too_cold = this->current_temperature < this->target_temperature_low;
const bool too_hot = this->current_temperature > this->target_temperature_high;
climate::ClimateMode target_mode;
climate::ClimateAction target_action;
if (too_cold) {
// too cold -> enable heating if possible, else idle
if (this->supports_heat_)
target_mode = climate::CLIMATE_MODE_HEAT;
target_action = climate::CLIMATE_ACTION_HEATING;
else
target_mode = climate::CLIMATE_MODE_OFF;
target_action = climate::CLIMATE_ACTION_OFF;
} else if (too_hot) {
// too hot -> enable cooling if possible, else idle
if (this->supports_cool_)
target_mode = climate::CLIMATE_MODE_COOL;
target_action = climate::CLIMATE_ACTION_COOLING;
else
target_mode = climate::CLIMATE_MODE_OFF;
target_action = climate::CLIMATE_ACTION_OFF;
} else {
// neither too hot nor too cold -> in range
if (this->supports_cool_ && this->supports_heat_) {
// if supports both ends, go to idle mode
target_mode = climate::CLIMATE_MODE_OFF;
target_action = climate::CLIMATE_ACTION_OFF;
} else {
// else use current mode and don't change (hysteresis)
target_mode = this->internal_mode_;
target_action = this->action;
}
}
this->switch_to_mode_(target_mode);
this->switch_to_action_(target_action);
}
void BangBangClimate::switch_to_mode_(climate::ClimateMode mode) {
if (mode == this->internal_mode_)
void BangBangClimate::switch_to_action_(climate::ClimateAction action) {
if (action == this->action)
// already in target mode
return;
@@ -100,14 +99,14 @@ void BangBangClimate::switch_to_mode_(climate::ClimateMode mode) {
this->prev_trigger_ = nullptr;
}
Trigger<> *trig;
switch (mode) {
case climate::CLIMATE_MODE_OFF:
switch (action) {
case climate::CLIMATE_ACTION_OFF:
trig = this->idle_trigger_;
break;
case climate::CLIMATE_MODE_COOL:
case climate::CLIMATE_ACTION_COOLING:
trig = this->cool_trigger_;
break;
case climate::CLIMATE_MODE_HEAT:
case climate::CLIMATE_ACTION_HEATING:
trig = this->heat_trigger_;
break;
default:
@@ -116,7 +115,7 @@ void BangBangClimate::switch_to_mode_(climate::ClimateMode mode) {
if (trig != nullptr) {
// trig should never be null, but still check so that we don't crash
trig->trigger();
this->internal_mode_ = mode;
this->action = action;
this->prev_trigger_ = trig;
this->publish_state();
}
@@ -43,7 +43,7 @@ class BangBangClimate : public climate::Climate, public Component {
void compute_state_();
/// Switch the climate device to the given climate mode.
void switch_to_mode_(climate::ClimateMode mode);
void switch_to_action_(climate::ClimateAction action);
/// The sensor used for getting the current temperature
sensor::Sensor *sensor_{nullptr};
@@ -74,11 +74,6 @@ class BangBangClimate : public climate::Climate, public Component {
* This is so that the previous trigger can be stopped before enabling a new one.
*/
Trigger<> *prev_trigger_{nullptr};
/** The climate mode that is currently active - for a `.mode = AUTO` this will
* contain the actual mode the device
*
*/
climate::ClimateMode internal_mode_{climate::CLIMATE_MODE_OFF};
BangBangClimateTargetTempConfig normal_config_{};
bool supports_away_{false};