mirror of
https://github.com/esphome/esphome.git
synced 2026-06-08 21:34:36 +08:00
Climate bang bang enhancements (#1061)
* Add fan support to bang bang controller * Fix heat-only and cool-only modes * Added support for all climate actions and modes * Fix up some comments * Fan_only mode behavior tweak * Updated test * Updated test, take 2 * Add accessor methods for easier use in lambadas * Revert "Add accessor methods for easier use in lambadas" This reverts commit f15713129cd5587242a08ad1e2ee37cbf075aa03. Don't code late at night when sleepy. * Fix single/dual setpoint support * Linted * Properly implement single-point, validation improvements * Another quick fix...sigh * Update tests * Update tests, take 2 * Revert "Update tests, take 2" This reverts commit 71bb7fccc53d95a7d221e80ea0a931fb3cfd9a0c. Nope. * Revert "Update tests" This reverts commit 42044291efaaf09858f29ab27bbc3aa9e8b80ee9. Nope 2. * Updated/fixed tests * Revert "Updated/fixed tests" This reverts commit a1a5b1c7db9a240b9da668b6e48abe1dd7910777. Taking a different approach. * Revert "Another quick fix...sigh" This reverts commit 6b1955724a2de3c2d1534ec206dd5794bbb5f568. Taking a different approach. * Revert "Properly implement single-point, validation improvements" This reverts commit f5bfff099e1dc58edd3898da8655c147adde2301. Taking a different approach. * Single/dual set point fixes, full validation * Fix test * Fix restore-on-boot, clean up comments * Decouple two-point/auto operation, more polish * One last away mode tweak * Added set point validation * Clean up over-publishing, always call action after boot * Add fan support to bang bang controller * Fix heat-only and cool-only modes * Added support for all climate actions and modes * Fix up some comments * Fan_only mode behavior tweak * Updated test * Updated test, take 2 * Add accessor methods for easier use in lambadas * Revert "Add accessor methods for easier use in lambadas" This reverts commit f15713129cd5587242a08ad1e2ee37cbf075aa03. Don't code late at night when sleepy. * Fix single/dual setpoint support * Linted * Properly implement single-point, validation improvements * Another quick fix...sigh * Update tests * Update tests, take 2 * Revert "Update tests, take 2" This reverts commit 71bb7fccc53d95a7d221e80ea0a931fb3cfd9a0c. Nope. * Revert "Update tests" This reverts commit 42044291efaaf09858f29ab27bbc3aa9e8b80ee9. Nope 2. * Updated/fixed tests * Revert "Updated/fixed tests" This reverts commit a1a5b1c7db9a240b9da668b6e48abe1dd7910777. Taking a different approach. * Revert "Another quick fix...sigh" This reverts commit 6b1955724a2de3c2d1534ec206dd5794bbb5f568. Taking a different approach. * Revert "Properly implement single-point, validation improvements" This reverts commit f5bfff099e1dc58edd3898da8655c147adde2301. Taking a different approach. * Single/dual set point fixes, full validation * Fix test * Fix restore-on-boot, clean up comments * Decouple two-point/auto operation, more polish * One last away mode tweak * Added set point validation * Clean up over-publishing, always call action after boot * Added refresh() function to allow easy on-device state refreshing
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -11,10 +11,13 @@ namespace bang_bang {
|
||||
struct BangBangClimateTargetTempConfig {
|
||||
public:
|
||||
BangBangClimateTargetTempConfig();
|
||||
BangBangClimateTargetTempConfig(float default_temperature);
|
||||
BangBangClimateTargetTempConfig(float default_temperature_low, float default_temperature_high);
|
||||
|
||||
float default_temperature{NAN};
|
||||
float default_temperature_low{NAN};
|
||||
float default_temperature_high{NAN};
|
||||
float hysteresis{NAN};
|
||||
};
|
||||
|
||||
class BangBangClimate : public climate::Climate, public Component {
|
||||
@@ -23,62 +26,243 @@ class BangBangClimate : public climate::Climate, public Component {
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
void set_hysteresis(float hysteresis);
|
||||
void set_sensor(sensor::Sensor *sensor);
|
||||
Trigger<> *get_idle_trigger() const;
|
||||
Trigger<> *get_cool_trigger() const;
|
||||
void set_supports_auto(bool supports_auto);
|
||||
void set_supports_cool(bool supports_cool);
|
||||
Trigger<> *get_heat_trigger() const;
|
||||
void set_supports_dry(bool supports_dry);
|
||||
void set_supports_fan_only(bool supports_fan_only);
|
||||
void set_supports_heat(bool supports_heat);
|
||||
void set_supports_fan_mode_on(bool supports_fan_mode_on);
|
||||
void set_supports_fan_mode_off(bool supports_fan_mode_off);
|
||||
void set_supports_fan_mode_auto(bool supports_fan_mode_auto);
|
||||
void set_supports_fan_mode_low(bool supports_fan_mode_low);
|
||||
void set_supports_fan_mode_medium(bool supports_fan_mode_medium);
|
||||
void set_supports_fan_mode_high(bool supports_fan_mode_high);
|
||||
void set_supports_fan_mode_middle(bool supports_fan_mode_middle);
|
||||
void set_supports_fan_mode_focus(bool supports_fan_mode_focus);
|
||||
void set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse);
|
||||
void set_supports_swing_mode_both(bool supports_swing_mode_both);
|
||||
void set_supports_swing_mode_horizontal(bool supports_swing_mode_horizontal);
|
||||
void set_supports_swing_mode_off(bool supports_swing_mode_off);
|
||||
void set_supports_swing_mode_vertical(bool supports_swing_mode_vertical);
|
||||
void set_supports_two_points(bool supports_two_points);
|
||||
|
||||
void set_normal_config(const BangBangClimateTargetTempConfig &normal_config);
|
||||
void set_away_config(const BangBangClimateTargetTempConfig &away_config);
|
||||
|
||||
Trigger<> *get_cool_action_trigger() const;
|
||||
Trigger<> *get_dry_action_trigger() const;
|
||||
Trigger<> *get_fan_only_action_trigger() const;
|
||||
Trigger<> *get_heat_action_trigger() const;
|
||||
Trigger<> *get_idle_action_trigger() const;
|
||||
Trigger<> *get_auto_mode_trigger() const;
|
||||
Trigger<> *get_cool_mode_trigger() const;
|
||||
Trigger<> *get_dry_mode_trigger() const;
|
||||
Trigger<> *get_fan_only_mode_trigger() const;
|
||||
Trigger<> *get_heat_mode_trigger() const;
|
||||
Trigger<> *get_off_mode_trigger() const;
|
||||
Trigger<> *get_fan_mode_on_trigger() const;
|
||||
Trigger<> *get_fan_mode_off_trigger() const;
|
||||
Trigger<> *get_fan_mode_auto_trigger() const;
|
||||
Trigger<> *get_fan_mode_low_trigger() const;
|
||||
Trigger<> *get_fan_mode_medium_trigger() const;
|
||||
Trigger<> *get_fan_mode_high_trigger() const;
|
||||
Trigger<> *get_fan_mode_middle_trigger() const;
|
||||
Trigger<> *get_fan_mode_focus_trigger() const;
|
||||
Trigger<> *get_fan_mode_diffuse_trigger() const;
|
||||
Trigger<> *get_swing_mode_both_trigger() const;
|
||||
Trigger<> *get_swing_mode_horizontal_trigger() const;
|
||||
Trigger<> *get_swing_mode_off_trigger() const;
|
||||
Trigger<> *get_swing_mode_vertical_trigger() const;
|
||||
/// Call triggers based on updated climate states (modes/actions)
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
/// Override control to change settings of the climate device.
|
||||
void control(const climate::ClimateCall &call) override;
|
||||
|
||||
/// Change the away setting, will reset target temperatures to defaults.
|
||||
void change_away_(bool away);
|
||||
|
||||
/// Return the traits of this controller.
|
||||
climate::ClimateTraits traits() override;
|
||||
|
||||
/// Re-compute the state of this climate controller.
|
||||
void compute_state_();
|
||||
/// Re-compute the required action of this climate controller.
|
||||
climate::ClimateAction compute_action_();
|
||||
|
||||
/// Switch the climate device to the given climate action.
|
||||
void switch_to_action_(climate::ClimateAction action);
|
||||
|
||||
/// Switch the climate device to the given climate fan mode.
|
||||
void switch_to_fan_mode_(climate::ClimateFanMode fan_mode);
|
||||
|
||||
/// Switch the climate device to the given climate mode.
|
||||
void switch_to_action_(climate::ClimateAction action);
|
||||
void switch_to_mode_(climate::ClimateMode mode);
|
||||
|
||||
/// Switch the climate device to the given climate swing mode.
|
||||
void switch_to_swing_mode_(climate::ClimateSwingMode swing_mode);
|
||||
|
||||
/// The sensor used for getting the current temperature
|
||||
sensor::Sensor *sensor_{nullptr};
|
||||
/** The trigger to call when the controller should switch to idle mode.
|
||||
*
|
||||
* In idle mode, the controller is assumed to have both heating and cooling disabled.
|
||||
*/
|
||||
Trigger<> *idle_trigger_;
|
||||
/** The trigger to call when the controller should switch to cooling mode.
|
||||
*/
|
||||
Trigger<> *cool_trigger_;
|
||||
/** Whether the controller supports cooling.
|
||||
*
|
||||
* A false value for this attribute means that the controller has no cooling action
|
||||
* (for example a thermostat, where only heating and not-heating is possible).
|
||||
*/
|
||||
bool supports_cool_{false};
|
||||
/** The trigger to call when the controller should switch to heating mode.
|
||||
*
|
||||
* A null value for this attribute means that the controller has no heating action
|
||||
* For example window blinds, where only cooling (blinds closed) and not-cooling
|
||||
* (blinds open) is possible.
|
||||
*/
|
||||
Trigger<> *heat_trigger_{nullptr};
|
||||
bool supports_heat_{false};
|
||||
/** A reference to the trigger that was previously active.
|
||||
*
|
||||
* This is so that the previous trigger can be stopped before enabling a new one.
|
||||
*/
|
||||
Trigger<> *prev_trigger_{nullptr};
|
||||
|
||||
BangBangClimateTargetTempConfig normal_config_{};
|
||||
/// Whether the controller supports auto/cooling/drying/fanning/heating.
|
||||
///
|
||||
/// A false value for any given attribute means that the controller has no such action
|
||||
/// (for example a thermostat, where only heating and not-heating is possible).
|
||||
bool supports_auto_{false};
|
||||
bool supports_cool_{false};
|
||||
bool supports_dry_{false};
|
||||
bool supports_fan_only_{false};
|
||||
bool supports_heat_{false};
|
||||
|
||||
/// Whether the controller supports turning on or off just the fan.
|
||||
///
|
||||
/// A false value for either attribute means that the controller has no fan on/off action
|
||||
/// (for example a thermostat, where independent control of the fan is not possible).
|
||||
bool supports_fan_mode_on_{false};
|
||||
bool supports_fan_mode_off_{false};
|
||||
|
||||
/// Whether the controller supports fan auto mode.
|
||||
///
|
||||
/// A false value for this attribute means that the controller has no fan-auto action
|
||||
/// (for example a thermostat, where independent control of the fan is not possible).
|
||||
bool supports_fan_mode_auto_{false};
|
||||
|
||||
/// Whether the controller supports various fan speeds and/or positions.
|
||||
///
|
||||
/// A false value for any given attribute means that the controller has no such fan action.
|
||||
bool supports_fan_mode_low_{false};
|
||||
bool supports_fan_mode_medium_{false};
|
||||
bool supports_fan_mode_high_{false};
|
||||
bool supports_fan_mode_middle_{false};
|
||||
bool supports_fan_mode_focus_{false};
|
||||
bool supports_fan_mode_diffuse_{false};
|
||||
|
||||
/// Whether the controller supports various swing modes.
|
||||
///
|
||||
/// A false value for any given attribute means that the controller has no such swing mode.
|
||||
bool supports_swing_mode_both_{false};
|
||||
bool supports_swing_mode_off_{false};
|
||||
bool supports_swing_mode_horizontal_{false};
|
||||
bool supports_swing_mode_vertical_{false};
|
||||
|
||||
/// Whether the controller supports two set points
|
||||
///
|
||||
/// A false value means that the controller has no such support.
|
||||
bool supports_two_points_{false};
|
||||
|
||||
/// Whether the controller supports an "away" mode
|
||||
///
|
||||
/// A false value means that the controller has no such mode.
|
||||
bool supports_away_{false};
|
||||
|
||||
/// The trigger to call when the controller should switch to cooling action/mode.
|
||||
///
|
||||
/// A null value for this attribute means that the controller has no cooling action
|
||||
/// For example electric heat, where only heating (power on) and not-heating
|
||||
/// (power off) is possible.
|
||||
Trigger<> *cool_action_trigger_{nullptr};
|
||||
Trigger<> *cool_mode_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch to dry (dehumidification) mode.
|
||||
///
|
||||
/// In dry mode, the controller is assumed to have both heating and cooling disabled,
|
||||
/// although the system may use its cooling mechanism to achieve drying.
|
||||
Trigger<> *dry_action_trigger_{nullptr};
|
||||
Trigger<> *dry_mode_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch to heating action/mode.
|
||||
///
|
||||
/// A null value for this attribute means that the controller has no heating action
|
||||
/// For example window blinds, where only cooling (blinds closed) and not-cooling
|
||||
/// (blinds open) is possible.
|
||||
Trigger<> *heat_action_trigger_{nullptr};
|
||||
Trigger<> *heat_mode_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch to auto mode.
|
||||
///
|
||||
/// In auto mode, the controller will enable heating/cooling as necessary and switch
|
||||
/// to idle when the temperature is within the thresholds/set points.
|
||||
Trigger<> *auto_mode_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch to idle action/off mode.
|
||||
///
|
||||
/// In these actions/modes, the controller is assumed to have both heating and cooling disabled.
|
||||
Trigger<> *idle_action_trigger_{nullptr};
|
||||
Trigger<> *off_mode_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch to fan-only action/mode.
|
||||
///
|
||||
/// In fan-only mode, the controller is assumed to have both heating and cooling disabled.
|
||||
/// The system should activate the fan only.
|
||||
Trigger<> *fan_only_action_trigger_{nullptr};
|
||||
Trigger<> *fan_only_mode_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch on the fan.
|
||||
Trigger<> *fan_mode_on_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch off the fan.
|
||||
Trigger<> *fan_mode_off_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "auto" mode.
|
||||
Trigger<> *fan_mode_auto_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "low" speed.
|
||||
Trigger<> *fan_mode_low_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "medium" speed.
|
||||
Trigger<> *fan_mode_medium_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "high" speed.
|
||||
Trigger<> *fan_mode_high_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "middle" position.
|
||||
Trigger<> *fan_mode_middle_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "focus" position.
|
||||
Trigger<> *fan_mode_focus_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the fan to "diffuse" position.
|
||||
Trigger<> *fan_mode_diffuse_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the swing mode to "both".
|
||||
Trigger<> *swing_mode_both_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the swing mode to "off".
|
||||
Trigger<> *swing_mode_off_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the swing mode to "horizontal".
|
||||
Trigger<> *swing_mode_horizontal_trigger_{nullptr};
|
||||
|
||||
/// The trigger to call when the controller should switch the swing mode to "vertical".
|
||||
Trigger<> *swing_mode_vertical_trigger_{nullptr};
|
||||
|
||||
/// A reference to the trigger that was previously active.
|
||||
///
|
||||
/// This is so that the previous trigger can be stopped before enabling a new one
|
||||
/// for each climate category (mode, action, fan_mode, swing_mode).
|
||||
Trigger<> *prev_action_trigger_{nullptr};
|
||||
Trigger<> *prev_fan_mode_trigger_{nullptr};
|
||||
Trigger<> *prev_mode_trigger_{nullptr};
|
||||
Trigger<> *prev_swing_mode_trigger_{nullptr};
|
||||
|
||||
/// Store previously-known states
|
||||
///
|
||||
/// These are used to determine when a trigger/action needs to be called
|
||||
climate::ClimateFanMode prev_fan_mode_{climate::CLIMATE_FAN_ON};
|
||||
climate::ClimateMode prev_mode_{climate::CLIMATE_MODE_OFF};
|
||||
climate::ClimateSwingMode prev_swing_mode_{climate::CLIMATE_SWING_OFF};
|
||||
|
||||
/// Temperature data for normal/home and away modes
|
||||
BangBangClimateTargetTempConfig normal_config_{};
|
||||
BangBangClimateTargetTempConfig away_config_{};
|
||||
|
||||
/// Hysteresis value used for computing climate actions
|
||||
float hysteresis_{0};
|
||||
|
||||
/// setup_complete_ blocks modifying/resetting the temps immediately after boot
|
||||
bool setup_complete_{false};
|
||||
};
|
||||
|
||||
} // namespace bang_bang
|
||||
|
||||
@@ -2,27 +2,107 @@ import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.components import climate, sensor
|
||||
from esphome.const import CONF_AWAY_CONFIG, CONF_COOL_ACTION, \
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_HEAT_ACTION, \
|
||||
CONF_ID, CONF_IDLE_ACTION, CONF_SENSOR
|
||||
from esphome.const import CONF_AUTO_MODE, CONF_AWAY_CONFIG, CONF_COOL_ACTION, CONF_COOL_MODE, \
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_DRY_ACTION, \
|
||||
CONF_DRY_MODE, CONF_FAN_MODE_ON_ACTION, CONF_FAN_MODE_OFF_ACTION, CONF_FAN_MODE_AUTO_ACTION, \
|
||||
CONF_FAN_MODE_LOW_ACTION, CONF_FAN_MODE_MEDIUM_ACTION, CONF_FAN_MODE_HIGH_ACTION, \
|
||||
CONF_FAN_MODE_MIDDLE_ACTION, CONF_FAN_MODE_FOCUS_ACTION, CONF_FAN_MODE_DIFFUSE_ACTION, \
|
||||
CONF_FAN_ONLY_ACTION, CONF_FAN_ONLY_MODE, CONF_HEAT_ACTION, CONF_HEAT_MODE, CONF_HYSTERESIS, \
|
||||
CONF_ID, CONF_IDLE_ACTION, CONF_OFF_MODE, CONF_SENSOR, CONF_SWING_BOTH_ACTION, \
|
||||
CONF_SWING_HORIZONTAL_ACTION, CONF_SWING_OFF_ACTION, CONF_SWING_VERTICAL_ACTION
|
||||
|
||||
bang_bang_ns = cg.esphome_ns.namespace('bang_bang')
|
||||
BangBangClimate = bang_bang_ns.class_('BangBangClimate', climate.Climate, cg.Component)
|
||||
BangBangClimateTargetTempConfig = bang_bang_ns.struct('BangBangClimateTargetTempConfig')
|
||||
|
||||
|
||||
def validate_bangbang(config):
|
||||
# verify corresponding climate action action exists for any defined climate mode action
|
||||
if CONF_COOL_MODE in config and CONF_COOL_ACTION not in config:
|
||||
raise cv.Invalid("{} must be defined to use {}".format(CONF_COOL_ACTION, CONF_COOL_MODE))
|
||||
if CONF_DRY_MODE in config and CONF_DRY_ACTION not in config:
|
||||
raise cv.Invalid("{} must be defined to use {}".format(CONF_DRY_ACTION, CONF_DRY_MODE))
|
||||
if CONF_FAN_ONLY_MODE in config and CONF_FAN_ONLY_ACTION not in config:
|
||||
raise cv.Invalid("{} must be defined to use {}".format(CONF_FAN_ONLY_ACTION,
|
||||
CONF_FAN_ONLY_MODE))
|
||||
if CONF_HEAT_MODE in config and CONF_HEAT_ACTION not in config:
|
||||
raise cv.Invalid("{} must be defined to use {}".format(CONF_HEAT_ACTION, CONF_HEAT_MODE))
|
||||
# verify corresponding default target temperature exists when a given climate action exists
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH not in config and (CONF_COOL_ACTION in config
|
||||
or CONF_FAN_ONLY_ACTION in config):
|
||||
raise cv.Invalid("{} must be defined when using {} or {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_COOL_ACTION, CONF_FAN_ONLY_ACTION))
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_LOW not in config and CONF_HEAT_ACTION in config:
|
||||
raise cv.Invalid("{} must be defined when using {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_HEAT_ACTION))
|
||||
# if a given climate action is NOT defined, it should not have a default target temperature
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config and (CONF_COOL_ACTION not in config
|
||||
and CONF_FAN_ONLY_ACTION not in config):
|
||||
raise cv.Invalid("{} is defined with no {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_COOL_ACTION))
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config and CONF_HEAT_ACTION not in config:
|
||||
raise cv.Invalid("{} is defined with no {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_HEAT_ACTION))
|
||||
|
||||
if CONF_AWAY_CONFIG in config:
|
||||
away = config[CONF_AWAY_CONFIG]
|
||||
# verify corresponding default target temperature exists when a given climate action exists
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH not in away and (CONF_COOL_ACTION in config or
|
||||
CONF_FAN_ONLY_ACTION in config):
|
||||
raise cv.Invalid("{} must be defined in away configuration when using {} or {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_COOL_ACTION, CONF_FAN_ONLY_ACTION))
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_LOW not in away and CONF_HEAT_ACTION in config:
|
||||
raise cv.Invalid("{} must be defined in away configuration when using {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_HEAT_ACTION))
|
||||
# if a given climate action is NOT defined, it should not have a default target temperature
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in away and (CONF_COOL_ACTION not in config and
|
||||
CONF_FAN_ONLY_ACTION not in config):
|
||||
raise cv.Invalid("{} is defined in away configuration with no {} or {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_HIGH, CONF_COOL_ACTION, CONF_FAN_ONLY_ACTION))
|
||||
if CONF_DEFAULT_TARGET_TEMPERATURE_LOW in away and CONF_HEAT_ACTION not in config:
|
||||
raise cv.Invalid("{} is defined in away configuration with no {}".format(
|
||||
CONF_DEFAULT_TARGET_TEMPERATURE_LOW, CONF_HEAT_ACTION))
|
||||
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(BangBangClimate),
|
||||
cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
||||
cv.Required(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature,
|
||||
cv.Required(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature,
|
||||
cv.Required(CONF_IDLE_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_COOL_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_DRY_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_ONLY_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_HEAT_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_AUTO_MODE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_COOL_MODE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_DRY_MODE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_ONLY_MODE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_HEAT_MODE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_OFF_MODE): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_ON_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_OFF_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_AUTO_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_LOW_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_MEDIUM_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_HIGH_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_MIDDLE_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_FOCUS_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_FAN_MODE_DIFFUSE_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_SWING_BOTH_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_SWING_HORIZONTAL_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_SWING_OFF_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_SWING_VERTICAL_ACTION): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature,
|
||||
cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature,
|
||||
cv.Optional(CONF_HYSTERESIS, default=0.5): cv.temperature,
|
||||
cv.Optional(CONF_AWAY_CONFIG): cv.Schema({
|
||||
cv.Required(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature,
|
||||
cv.Required(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature,
|
||||
cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_HIGH): cv.temperature,
|
||||
cv.Optional(CONF_DEFAULT_TARGET_TEMPERATURE_LOW): cv.temperature,
|
||||
}),
|
||||
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_COOL_ACTION, CONF_HEAT_ACTION))
|
||||
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_COOL_ACTION, CONF_DRY_ACTION,
|
||||
CONF_FAN_ONLY_ACTION, CONF_HEAT_ACTION),
|
||||
validate_bangbang)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
@@ -30,28 +110,145 @@ def to_code(config):
|
||||
yield cg.register_component(var, config)
|
||||
yield climate.register_climate(var, config)
|
||||
|
||||
auto_mode_available = CONF_HEAT_ACTION in config and CONF_COOL_ACTION in config
|
||||
two_points_available = CONF_HEAT_ACTION in config and (CONF_COOL_ACTION in config or
|
||||
CONF_FAN_ONLY_ACTION in config)
|
||||
|
||||
sens = yield cg.get_variable(config[CONF_SENSOR])
|
||||
cg.add(var.set_sensor(sens))
|
||||
cg.add(var.set_hysteresis(config[CONF_HYSTERESIS]))
|
||||
|
||||
normal_config = BangBangClimateTargetTempConfig(
|
||||
config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW],
|
||||
config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
|
||||
)
|
||||
if two_points_available is True:
|
||||
cg.add(var.set_supports_two_points(True))
|
||||
normal_config = BangBangClimateTargetTempConfig(
|
||||
config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW],
|
||||
config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
|
||||
)
|
||||
elif CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in config:
|
||||
cg.add(var.set_supports_two_points(False))
|
||||
normal_config = BangBangClimateTargetTempConfig(
|
||||
config[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
|
||||
)
|
||||
elif CONF_DEFAULT_TARGET_TEMPERATURE_LOW in config:
|
||||
cg.add(var.set_supports_two_points(False))
|
||||
normal_config = BangBangClimateTargetTempConfig(
|
||||
config[CONF_DEFAULT_TARGET_TEMPERATURE_LOW]
|
||||
)
|
||||
cg.add(var.set_normal_config(normal_config))
|
||||
|
||||
yield automation.build_automation(var.get_idle_trigger(), [], config[CONF_IDLE_ACTION])
|
||||
yield automation.build_automation(var.get_idle_action_trigger(), [],
|
||||
config[CONF_IDLE_ACTION])
|
||||
|
||||
if auto_mode_available is True:
|
||||
cg.add(var.set_supports_auto(True))
|
||||
else:
|
||||
cg.add(var.set_supports_auto(False))
|
||||
|
||||
if CONF_COOL_ACTION in config:
|
||||
yield automation.build_automation(var.get_cool_trigger(), [], config[CONF_COOL_ACTION])
|
||||
yield automation.build_automation(var.get_cool_action_trigger(), [],
|
||||
config[CONF_COOL_ACTION])
|
||||
cg.add(var.set_supports_cool(True))
|
||||
if CONF_DRY_ACTION in config:
|
||||
yield automation.build_automation(var.get_dry_action_trigger(), [],
|
||||
config[CONF_DRY_ACTION])
|
||||
cg.add(var.set_supports_dry(True))
|
||||
if CONF_FAN_ONLY_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_only_action_trigger(), [],
|
||||
config[CONF_FAN_ONLY_ACTION])
|
||||
cg.add(var.set_supports_fan_only(True))
|
||||
if CONF_HEAT_ACTION in config:
|
||||
yield automation.build_automation(var.get_heat_trigger(), [], config[CONF_HEAT_ACTION])
|
||||
yield automation.build_automation(var.get_heat_action_trigger(), [],
|
||||
config[CONF_HEAT_ACTION])
|
||||
cg.add(var.set_supports_heat(True))
|
||||
if CONF_AUTO_MODE in config:
|
||||
yield automation.build_automation(var.get_auto_mode_trigger(), [],
|
||||
config[CONF_AUTO_MODE])
|
||||
if CONF_COOL_MODE in config:
|
||||
yield automation.build_automation(var.get_cool_mode_trigger(), [],
|
||||
config[CONF_COOL_MODE])
|
||||
cg.add(var.set_supports_cool(True))
|
||||
if CONF_DRY_MODE in config:
|
||||
yield automation.build_automation(var.get_dry_mode_trigger(), [],
|
||||
config[CONF_DRY_MODE])
|
||||
cg.add(var.set_supports_dry(True))
|
||||
if CONF_FAN_ONLY_MODE in config:
|
||||
yield automation.build_automation(var.get_fan_only_mode_trigger(), [],
|
||||
config[CONF_FAN_ONLY_MODE])
|
||||
cg.add(var.set_supports_fan_only(True))
|
||||
if CONF_HEAT_MODE in config:
|
||||
yield automation.build_automation(var.get_heat_mode_trigger(), [],
|
||||
config[CONF_HEAT_MODE])
|
||||
cg.add(var.set_supports_heat(True))
|
||||
if CONF_OFF_MODE in config:
|
||||
yield automation.build_automation(var.get_off_mode_trigger(), [],
|
||||
config[CONF_OFF_MODE])
|
||||
if CONF_FAN_MODE_ON_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_on_trigger(), [],
|
||||
config[CONF_FAN_MODE_ON_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_on(True))
|
||||
if CONF_FAN_MODE_OFF_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_off_trigger(), [],
|
||||
config[CONF_FAN_MODE_OFF_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_off(True))
|
||||
if CONF_FAN_MODE_AUTO_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_auto_trigger(), [],
|
||||
config[CONF_FAN_MODE_AUTO_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_auto(True))
|
||||
if CONF_FAN_MODE_LOW_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_low_trigger(), [],
|
||||
config[CONF_FAN_MODE_LOW_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_low(True))
|
||||
if CONF_FAN_MODE_MEDIUM_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_medium_trigger(), [],
|
||||
config[CONF_FAN_MODE_MEDIUM_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_medium(True))
|
||||
if CONF_FAN_MODE_HIGH_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_high_trigger(), [],
|
||||
config[CONF_FAN_MODE_HIGH_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_high(True))
|
||||
if CONF_FAN_MODE_MIDDLE_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_middle_trigger(), [],
|
||||
config[CONF_FAN_MODE_MIDDLE_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_middle(True))
|
||||
if CONF_FAN_MODE_FOCUS_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_focus_trigger(), [],
|
||||
config[CONF_FAN_MODE_FOCUS_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_focus(True))
|
||||
if CONF_FAN_MODE_DIFFUSE_ACTION in config:
|
||||
yield automation.build_automation(var.get_fan_mode_diffuse_trigger(), [],
|
||||
config[CONF_FAN_MODE_DIFFUSE_ACTION])
|
||||
cg.add(var.set_supports_fan_mode_diffuse(True))
|
||||
if CONF_SWING_BOTH_ACTION in config:
|
||||
yield automation.build_automation(var.get_swing_mode_both_trigger(), [],
|
||||
config[CONF_SWING_BOTH_ACTION])
|
||||
cg.add(var.set_supports_swing_mode_both(True))
|
||||
if CONF_SWING_HORIZONTAL_ACTION in config:
|
||||
yield automation.build_automation(var.get_swing_mode_horizontal_trigger(), [],
|
||||
config[CONF_SWING_HORIZONTAL_ACTION])
|
||||
cg.add(var.set_supports_swing_mode_horizontal(True))
|
||||
if CONF_SWING_OFF_ACTION in config:
|
||||
yield automation.build_automation(var.get_swing_mode_off_trigger(), [],
|
||||
config[CONF_SWING_OFF_ACTION])
|
||||
cg.add(var.set_supports_swing_mode_off(True))
|
||||
if CONF_SWING_VERTICAL_ACTION in config:
|
||||
yield automation.build_automation(var.get_swing_mode_vertical_trigger(), [],
|
||||
config[CONF_SWING_VERTICAL_ACTION])
|
||||
cg.add(var.set_supports_swing_mode_vertical(True))
|
||||
|
||||
if CONF_AWAY_CONFIG in config:
|
||||
away = config[CONF_AWAY_CONFIG]
|
||||
away_config = BangBangClimateTargetTempConfig(
|
||||
away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW],
|
||||
away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
|
||||
)
|
||||
|
||||
if two_points_available is True:
|
||||
away_config = BangBangClimateTargetTempConfig(
|
||||
away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW],
|
||||
away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
|
||||
)
|
||||
elif CONF_DEFAULT_TARGET_TEMPERATURE_HIGH in away:
|
||||
away_config = BangBangClimateTargetTempConfig(
|
||||
away[CONF_DEFAULT_TARGET_TEMPERATURE_HIGH]
|
||||
)
|
||||
elif CONF_DEFAULT_TARGET_TEMPERATURE_LOW in away:
|
||||
away_config = BangBangClimateTargetTempConfig(
|
||||
away[CONF_DEFAULT_TARGET_TEMPERATURE_LOW]
|
||||
)
|
||||
cg.add(var.set_away_config(away_config))
|
||||
|
||||
@@ -44,6 +44,7 @@ CONF_ASSUMED_STATE = 'assumed_state'
|
||||
CONF_AT = 'at'
|
||||
CONF_ATTENUATION = 'attenuation'
|
||||
CONF_AUTH = 'auth'
|
||||
CONF_AUTO_MODE = 'auto_mode'
|
||||
CONF_AUTOMATION_ID = 'automation_id'
|
||||
CONF_AVAILABILITY = 'availability'
|
||||
CONF_AWAY = 'away'
|
||||
@@ -101,6 +102,7 @@ CONF_CONDITION = 'condition'
|
||||
CONF_CONDITION_ID = 'condition_id'
|
||||
CONF_CONDUCTIVITY = 'conductivity'
|
||||
CONF_COOL_ACTION = 'cool_action'
|
||||
CONF_COOL_MODE = 'cool_mode'
|
||||
CONF_COUNT_MODE = 'count_mode'
|
||||
CONF_CRON = 'cron'
|
||||
CONF_CS_PIN = 'cs_pin'
|
||||
@@ -139,6 +141,8 @@ CONF_DIV_RATIO = 'div_ratio'
|
||||
CONF_DNS1 = 'dns1'
|
||||
CONF_DNS2 = 'dns2'
|
||||
CONF_DOMAIN = 'domain'
|
||||
CONF_DRY_ACTION = 'dry_action'
|
||||
CONF_DRY_MODE = 'dry_mode'
|
||||
CONF_DUMP = 'dump'
|
||||
CONF_DURATION = 'duration'
|
||||
CONF_ECHO_PIN = 'echo_pin'
|
||||
@@ -158,6 +162,17 @@ CONF_EXTERNAL_VCC = 'external_vcc'
|
||||
CONF_FALLING_EDGE = 'falling_edge'
|
||||
CONF_FAMILY = 'family'
|
||||
CONF_FAN_MODE = 'fan_mode'
|
||||
CONF_FAN_MODE_AUTO_ACTION = 'fan_mode_auto_action'
|
||||
CONF_FAN_MODE_DIFFUSE_ACTION = 'fan_mode_diffuse_action'
|
||||
CONF_FAN_MODE_FOCUS_ACTION = 'fan_mode_focus_action'
|
||||
CONF_FAN_MODE_HIGH_ACTION = 'fan_mode_high_action'
|
||||
CONF_FAN_MODE_LOW_ACTION = 'fan_mode_low_action'
|
||||
CONF_FAN_MODE_MEDIUM_ACTION = 'fan_mode_medium_action'
|
||||
CONF_FAN_MODE_MIDDLE_ACTION = 'fan_mode_middle_action'
|
||||
CONF_FAN_MODE_OFF_ACTION = 'fan_mode_off_action'
|
||||
CONF_FAN_MODE_ON_ACTION = 'fan_mode_on_action'
|
||||
CONF_FAN_ONLY_ACTION = 'fan_only_action'
|
||||
CONF_FAN_ONLY_MODE = 'fan_only_mode'
|
||||
CONF_FAST_CONNECT = 'fast_connect'
|
||||
CONF_FILE = 'file'
|
||||
CONF_FILTER = 'filter'
|
||||
@@ -182,6 +197,7 @@ CONF_GROUP = 'group'
|
||||
CONF_HARDWARE_UART = 'hardware_uart'
|
||||
CONF_HEARTBEAT = 'heartbeat'
|
||||
CONF_HEAT_ACTION = 'heat_action'
|
||||
CONF_HEAT_MODE = 'heat_mode'
|
||||
CONF_HEATER = 'heater'
|
||||
CONF_HIDDEN = 'hidden'
|
||||
CONF_HIGH = 'high'
|
||||
@@ -189,6 +205,7 @@ CONF_HIGH_VOLTAGE_REFERENCE = 'high_voltage_reference'
|
||||
CONF_HOUR = 'hour'
|
||||
CONF_HOURS = 'hours'
|
||||
CONF_HUMIDITY = 'humidity'
|
||||
CONF_HYSTERESIS = "hysteresis"
|
||||
CONF_I2C = 'i2c'
|
||||
CONF_I2C_ID = 'i2c_id'
|
||||
CONF_ICON = 'icon'
|
||||
@@ -284,6 +301,7 @@ CONF_NUM_CHANNELS = 'num_channels'
|
||||
CONF_NUM_CHIPS = 'num_chips'
|
||||
CONF_NUM_LEDS = 'num_leds'
|
||||
CONF_NUMBER = 'number'
|
||||
CONF_OFF_MODE = 'off_mode'
|
||||
CONF_OFFSET = 'offset'
|
||||
CONF_ON = 'on'
|
||||
CONF_ON_BLE_ADVERTISE = 'on_ble_advertise'
|
||||
@@ -448,7 +466,11 @@ CONF_STOP_ACTION = 'stop_action'
|
||||
CONF_SUBNET = 'subnet'
|
||||
CONF_SUPPORTS_COOL = 'supports_cool'
|
||||
CONF_SUPPORTS_HEAT = 'supports_heat'
|
||||
CONF_SWING_BOTH_ACTION = 'swing_both_action'
|
||||
CONF_SWING_HORIZONTAL_ACTION = 'swing_horizontal_action'
|
||||
CONF_SWING_MODE = 'swing_mode'
|
||||
CONF_SWING_OFF_ACTION = 'swing_off_action'
|
||||
CONF_SWING_VERTICAL_ACTION = 'swing_vertical_action'
|
||||
CONF_SWITCHES = 'switches'
|
||||
CONF_SYNC = 'sync'
|
||||
CONF_TABLET = 'tablet'
|
||||
|
||||
@@ -615,6 +615,49 @@ climate:
|
||||
- switch.turn_on: gpio_switch2
|
||||
heat_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
dry_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
fan_only_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
auto_mode:
|
||||
- switch.turn_on: gpio_switch2
|
||||
off_mode:
|
||||
- switch.turn_on: gpio_switch1
|
||||
heat_mode:
|
||||
- switch.turn_on: gpio_switch2
|
||||
cool_mode:
|
||||
- switch.turn_on: gpio_switch1
|
||||
dry_mode:
|
||||
- switch.turn_on: gpio_switch2
|
||||
fan_only_mode:
|
||||
- switch.turn_on: gpio_switch1
|
||||
fan_mode_auto_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
fan_mode_on_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
fan_mode_off_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
fan_mode_low_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
fan_mode_medium_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
fan_mode_high_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
fan_mode_middle_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
fan_mode_focus_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
fan_mode_diffuse_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
swing_off_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
swing_horizontal_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
swing_vertical_action:
|
||||
- switch.turn_on: gpio_switch1
|
||||
swing_both_action:
|
||||
- switch.turn_on: gpio_switch2
|
||||
hysteresis: 0.2
|
||||
away_config:
|
||||
default_target_temperature_low: 16°C
|
||||
default_target_temperature_high: 20°C
|
||||
|
||||
Reference in New Issue
Block a user