[core] Replace custom esphome::optional with std::optional (#14368)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
J. Nick Koston
2026-03-03 15:14:05 -10:00
committed by GitHub
parent 43a6fe9b6c
commit 9371159a7e
92 changed files with 723 additions and 701 deletions

View File

@@ -63,8 +63,9 @@ void Am43Component::control(const CoverCall &call) {
ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
}
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto opt_pos = call.get_position();
if (opt_pos.has_value()) {
auto pos = *opt_pos;
if (this->invert_position_)
pos = 1 - pos;

View File

@@ -24,8 +24,9 @@ void Anova::loop() {
}
void Anova::control(const ClimateCall &call) {
if (call.get_mode().has_value()) {
ClimateMode mode = *call.get_mode();
auto mode_val = call.get_mode();
if (mode_val.has_value()) {
ClimateMode mode = *mode_val;
AnovaPacket *pkt;
switch (mode) {
case climate::CLIMATE_MODE_OFF:
@@ -45,8 +46,9 @@ void Anova::control(const ClimateCall &call) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
}
if (call.get_target_temperature().has_value()) {
auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
auto target_temp = call.get_target_temperature();
if (target_temp.has_value()) {
auto *pkt = this->codec_->get_set_target_temp_request(*target_temp);
auto status =
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);

View File

@@ -47,7 +47,7 @@ void BalluClimate::transmit_state() {
remote_state[11] = 0x1e;
// Fan speed
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_HIGH:
remote_state[4] |= BALLU_FAN_HIGH;
break;

View File

@@ -45,17 +45,21 @@ void BangBangClimate::setup() {
}
void BangBangClimate::control(const climate::ClimateCall &call) {
if (call.get_mode().has_value()) {
this->mode = *call.get_mode();
auto mode = call.get_mode();
if (mode.has_value()) {
this->mode = *mode;
}
if (call.get_target_temperature_low().has_value()) {
this->target_temperature_low = *call.get_target_temperature_low();
auto target_temperature_low = call.get_target_temperature_low();
if (target_temperature_low.has_value()) {
this->target_temperature_low = *target_temperature_low;
}
if (call.get_target_temperature_high().has_value()) {
this->target_temperature_high = *call.get_target_temperature_high();
auto target_temperature_high = call.get_target_temperature_high();
if (target_temperature_high.has_value()) {
this->target_temperature_high = *target_temperature_high;
}
if (call.get_preset().has_value()) {
this->change_away_(*call.get_preset() == climate::CLIMATE_PRESET_AWAY);
auto preset = call.get_preset();
if (preset.has_value()) {
this->change_away_(*preset == climate::CLIMATE_PRESET_AWAY);
}
this->compute_state_();

View File

@@ -96,8 +96,9 @@ void BedJetClimate::control(const ClimateCall &call) {
return;
}
if (call.get_mode().has_value()) {
ClimateMode mode = *call.get_mode();
auto mode_opt = call.get_mode();
if (mode_opt.has_value()) {
ClimateMode mode = *mode_opt;
bool button_result;
switch (mode) {
case CLIMATE_MODE_OFF:
@@ -125,8 +126,9 @@ void BedJetClimate::control(const ClimateCall &call) {
}
}
if (call.get_target_temperature().has_value()) {
auto target_temp = *call.get_target_temperature();
auto target_temp_opt = call.get_target_temperature();
if (target_temp_opt.has_value()) {
auto target_temp = *target_temp_opt;
auto result = this->parent_->set_target_temp(target_temp);
if (result) {
@@ -134,8 +136,9 @@ void BedJetClimate::control(const ClimateCall &call) {
}
}
if (call.get_preset().has_value()) {
ClimatePreset preset = *call.get_preset();
auto preset_opt = call.get_preset();
if (preset_opt.has_value()) {
ClimatePreset preset = *preset_opt;
bool result;
if (preset == CLIMATE_PRESET_BOOST) {
@@ -187,10 +190,11 @@ void BedJetClimate::control(const ClimateCall &call) {
}
}
if (call.get_fan_mode().has_value()) {
auto fan_mode_opt = call.get_fan_mode();
if (fan_mode_opt.has_value()) {
// Climate fan mode only supports low/med/high, but the BedJet supports 5-100% increments.
// We can still support a ClimateCall that requests low/med/high, and just translate it to a step increment here.
auto fan_mode = *call.get_fan_mode();
auto fan_mode = *fan_mode_opt;
bool result;
if (fan_mode == CLIMATE_FAN_LOW) {
result = this->parent_->set_fan_speed(20);

View File

@@ -19,7 +19,8 @@ void BedJetFan::control(const fan::FanCall &call) {
}
bool did_change = false;
if (call.get_state().has_value() && this->state != *call.get_state()) {
auto state_opt = call.get_state();
if (state_opt.has_value() && this->state != *state_opt) {
// Turning off is easy:
if (this->state && this->parent_->button_off()) {
this->state = false;
@@ -36,8 +37,9 @@ void BedJetFan::control(const fan::FanCall &call) {
}
// ignore speed changes if not on or turning on
if (this->state && call.get_speed().has_value()) {
auto speed = *call.get_speed();
auto speed_opt = call.get_speed();
if (this->state && speed_opt.has_value()) {
auto speed = *speed_opt;
if (speed >= 1) {
this->speed = speed;
// Fan.speed is 1-20, but Bedjet expects 0-19, so subtract 1

View File

@@ -18,12 +18,15 @@ fan::FanTraits BinaryFan::get_traits() {
return fan::FanTraits(this->oscillating_ != nullptr, false, this->direction_ != nullptr, 0);
}
void BinaryFan::control(const fan::FanCall &call) {
if (call.get_state().has_value())
this->state = *call.get_state();
if (call.get_oscillating().has_value())
this->oscillating = *call.get_oscillating();
if (call.get_direction().has_value())
this->direction = *call.get_direction();
auto state = call.get_state();
if (state.has_value())
this->state = *state;
auto oscillating = call.get_oscillating();
if (oscillating.has_value())
this->oscillating = *oscillating;
auto direction = call.get_direction();
if (direction.has_value())
this->direction = *direction;
this->write_state_();
this->publish_state();

View File

@@ -76,11 +76,12 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
}
break;
case MATCH_BY_IBEACON_UUID:
if (!device.get_ibeacon().has_value()) {
auto maybe_ibeacon = device.get_ibeacon();
if (!maybe_ibeacon.has_value()) {
return false;
}
auto ibeacon = device.get_ibeacon().value();
auto ibeacon = *maybe_ibeacon;
if (this->ibeacon_uuid_ != ibeacon.get_uuid()) {
return false;

View File

@@ -74,11 +74,12 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
}
break;
case MATCH_BY_IBEACON_UUID:
if (!device.get_ibeacon().has_value()) {
auto maybe_ibeacon = device.get_ibeacon();
if (!maybe_ibeacon.has_value()) {
return false;
}
auto ibeacon = device.get_ibeacon().value();
auto ibeacon = *maybe_ibeacon;
if (this->ibeacon_uuid_ != ibeacon.get_uuid()) {
return false;

View File

@@ -71,16 +71,21 @@ void ClimateIR::setup() {
}
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();
if (call.get_fan_mode().has_value())
this->fan_mode = *call.get_fan_mode();
if (call.get_swing_mode().has_value())
this->swing_mode = *call.get_swing_mode();
if (call.get_preset().has_value())
this->preset = *call.get_preset();
auto mode = call.get_mode();
if (mode.has_value())
this->mode = *mode;
auto target_temperature = call.get_target_temperature();
if (target_temperature.has_value())
this->target_temperature = *target_temperature;
auto fan_mode = call.get_fan_mode();
if (fan_mode.has_value())
this->fan_mode = fan_mode;
auto swing_mode = call.get_swing_mode();
if (swing_mode.has_value())
this->swing_mode = *swing_mode;
auto preset = call.get_preset();
if (preset.has_value())
this->preset = preset;
this->transmit_state();
this->publish_state();
}

View File

@@ -79,7 +79,7 @@ void LgIrClimate::transmit_state() {
if (this->mode == climate::CLIMATE_MODE_OFF) {
remote_state |= FAN_AUTO;
} else {
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_HIGH:
remote_state |= FAN_MAX;
break;

View File

@@ -23,7 +23,8 @@ class LgIrClimate : public climate_ir::ClimateIR {
void control(const climate::ClimateCall &call) override {
this->send_swing_cmd_ = call.get_swing_mode().has_value();
// swing resets after unit powered off
if (call.get_mode().has_value() && *call.get_mode() == climate::CLIMATE_MODE_OFF)
auto mode = call.get_mode();
if (mode.has_value() && *mode == climate::CLIMATE_MODE_OFF)
this->swing_mode = climate::CLIMATE_SWING_OFF;
climate_ir::ClimateIR::control(call);
}

View File

@@ -83,7 +83,7 @@ void CoolixClimate::transmit_state() {
this->fan_mode = climate::CLIMATE_FAN_AUTO;
remote_state |= COOLIX_FAN_MODE_AUTO_DRY;
} else {
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_HIGH:
remote_state |= COOLIX_FAN_MAX;
break;

View File

@@ -23,7 +23,8 @@ class CoolixClimate : public climate_ir::ClimateIR {
void control(const climate::ClimateCall &call) override {
send_swing_cmd_ = call.get_swing_mode().has_value();
// swing resets after unit powered off
if (call.get_mode().has_value() && *call.get_mode() == climate::CLIMATE_MODE_OFF)
auto mode = call.get_mode();
if (mode.has_value() && *mode == climate::CLIMATE_MODE_OFF)
this->swing_mode = climate::CLIMATE_SWING_OFF;
climate_ir::ClimateIR::control(call);
}

View File

@@ -38,12 +38,15 @@ cover::CoverTraits CopyCover::get_traits() {
void CopyCover::control(const cover::CoverCall &call) {
auto call2 = source_->make_call();
call2.set_stop(call.get_stop());
if (call.get_tilt().has_value())
call2.set_tilt(*call.get_tilt());
if (call.get_position().has_value())
call2.set_position(*call.get_position());
if (call.get_tilt().has_value())
call2.set_tilt(*call.get_tilt());
auto tilt = call.get_tilt();
if (tilt.has_value())
call2.set_tilt(*tilt);
auto position = call.get_position();
if (position.has_value())
call2.set_position(*position);
auto tilt2 = call.get_tilt();
if (tilt2.has_value())
call2.set_tilt(*tilt2);
call2.perform();
}

View File

@@ -45,14 +45,18 @@ fan::FanTraits CopyFan::get_traits() {
void CopyFan::control(const fan::FanCall &call) {
auto call2 = source_->make_call();
if (call.get_state().has_value())
call2.set_state(*call.get_state());
if (call.get_oscillating().has_value())
call2.set_oscillating(*call.get_oscillating());
if (call.get_speed().has_value())
call2.set_speed(*call.get_speed());
if (call.get_direction().has_value())
call2.set_direction(*call.get_direction());
auto state = call.get_state();
if (state.has_value())
call2.set_state(*state);
auto oscillating = call.get_oscillating();
if (oscillating.has_value())
call2.set_oscillating(*oscillating);
auto speed = call.get_speed();
if (speed.has_value())
call2.set_speed(*speed);
auto direction = call.get_direction();
if (direction.has_value())
call2.set_direction(*direction);
if (call.has_preset_mode())
call2.set_preset_mode(call.get_preset_mode());
call2.perform();

View File

@@ -11,8 +11,9 @@ void CopySelect::setup() {
traits.set_options(source_->traits.get_options());
if (source_->has_state())
this->publish_state(source_->active_index().value());
auto idx = this->source_->active_index();
if (idx.has_value())
this->publish_state(*idx);
}
void CopySelect::dump_config() { LOG_SELECT("", "Copy Select", this); }

View File

@@ -37,8 +37,9 @@ void CurrentBasedCover::control(const CoverCall &call) {
}
}
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto opt_pos = call.get_position();
if (opt_pos.has_value()) {
auto pos = *opt_pos;
if (fabsf(this->position - pos) < 0.01) {
// already at target
} else {

View File

@@ -94,7 +94,7 @@ uint8_t DaikinClimate::operation_mode_() const {
uint16_t DaikinClimate::fan_speed_() const {
uint16_t fan_speed;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_QUIET:
fan_speed = DAIKIN_FAN_SILENT << 8;
break;

View File

@@ -176,7 +176,7 @@ uint8_t DaikinArcClimate::operation_mode_() {
uint16_t DaikinArcClimate::fan_speed_() {
uint16_t fan_speed;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
fan_speed = DAIKIN_FAN_1 << 8;
break;
@@ -485,8 +485,9 @@ bool DaikinArcClimate::on_receive(remote_base::RemoteReceiveData data) {
}
void DaikinArcClimate::control(const climate::ClimateCall &call) {
if (call.get_target_humidity().has_value()) {
this->target_humidity = *call.get_target_humidity();
auto target_humidity = call.get_target_humidity();
if (target_humidity.has_value()) {
this->target_humidity = *target_humidity;
}
climate_ir::ClimateIR::control(call);
}

View File

@@ -111,7 +111,7 @@ uint8_t DaikinBrcClimate::operation_mode_() {
uint8_t DaikinBrcClimate::fan_speed_swing_() {
uint16_t fan_speed;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
fan_speed = DAIKIN_BRC_FAN_1;
break;

View File

@@ -15,7 +15,7 @@ void DeepSleepComponent::dump_config_platform_() {}
bool DeepSleepComponent::prepare_to_sleep_() { return true; }
void DeepSleepComponent::deep_sleep_() {
ESP.deepSleep(*this->sleep_duration_); // NOLINT(readability-static-accessed-through-instance)
ESP.deepSleep(this->sleep_duration_.value_or(0)); // NOLINT(readability-static-accessed-through-instance)
}
} // namespace deep_sleep

View File

@@ -64,7 +64,7 @@ uint8_t DelonghiClimate::operation_mode_() {
uint16_t DelonghiClimate::fan_speed_() {
uint16_t fan_speed;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
fan_speed = DELONGHI_FAN_LOW;
break;

View File

@@ -29,10 +29,11 @@ class DemoAlarmControlPanel : public AlarmControlPanel, public Component {
protected:
void control(const AlarmControlPanelCall &call) override {
auto state = call.get_state().value_or(ACP_STATE_DISARMED);
auto code = call.get_code();
switch (state) {
case ACP_STATE_ARMED_AWAY:
if (this->get_requires_code_to_arm() && call.get_code().has_value()) {
if (call.get_code().value() != "1234") {
if (this->get_requires_code_to_arm() && code.has_value()) {
if (*code != "1234") {
this->status_momentary_error("invalid_code", 5000);
return;
}
@@ -40,8 +41,8 @@ class DemoAlarmControlPanel : public AlarmControlPanel, public Component {
this->publish_state(ACP_STATE_ARMED_AWAY);
break;
case ACP_STATE_DISARMED:
if (this->get_requires_code() && call.get_code().has_value()) {
if (call.get_code().value() != "1234") {
if (this->get_requires_code() && code.has_value()) {
if (*code != "1234") {
this->status_momentary_error("invalid_code", 5000);
return;
}

View File

@@ -45,33 +45,31 @@ class DemoClimate : public climate::Climate, public Component {
protected:
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();
}
if (call.get_target_temperature_low().has_value()) {
this->target_temperature_low = *call.get_target_temperature_low();
}
if (call.get_target_temperature_high().has_value()) {
this->target_temperature_high = *call.get_target_temperature_high();
}
if (call.get_fan_mode().has_value()) {
this->set_fan_mode_(*call.get_fan_mode());
}
if (call.get_swing_mode().has_value()) {
this->swing_mode = *call.get_swing_mode();
}
if (call.has_custom_fan_mode()) {
auto mode = call.get_mode();
if (mode.has_value())
this->mode = *mode;
auto target_temperature = call.get_target_temperature();
if (target_temperature.has_value())
this->target_temperature = *target_temperature;
auto target_temperature_low = call.get_target_temperature_low();
if (target_temperature_low.has_value())
this->target_temperature_low = *target_temperature_low;
auto target_temperature_high = call.get_target_temperature_high();
if (target_temperature_high.has_value())
this->target_temperature_high = *target_temperature_high;
auto fan_mode = call.get_fan_mode();
if (fan_mode.has_value())
this->set_fan_mode_(*fan_mode);
auto swing_mode = call.get_swing_mode();
if (swing_mode.has_value())
this->swing_mode = *swing_mode;
if (call.has_custom_fan_mode())
this->set_custom_fan_mode_(call.get_custom_fan_mode());
}
if (call.get_preset().has_value()) {
this->set_preset_(*call.get_preset());
}
if (call.has_custom_preset()) {
auto preset = call.get_preset();
if (preset.has_value())
this->set_preset_(*preset);
if (call.has_custom_preset())
this->set_custom_preset_(call.get_custom_preset());
}
this->publish_state();
}
climate::ClimateTraits traits() override {

View File

@@ -38,8 +38,9 @@ class DemoCover : public cover::Cover, public Component {
protected:
void control(const cover::CoverCall &call) override {
if (call.get_position().has_value()) {
float target = *call.get_position();
auto pos = call.get_position();
if (pos.has_value()) {
float target = *pos;
this->current_operation =
target > this->position ? cover::COVER_OPERATION_OPENING : cover::COVER_OPERATION_CLOSING;
@@ -49,8 +50,9 @@ class DemoCover : public cover::Cover, public Component {
this->publish_state();
});
}
if (call.get_tilt().has_value()) {
this->tilt = *call.get_tilt();
auto tilt = call.get_tilt();
if (tilt.has_value()) {
this->tilt = *tilt;
}
if (call.get_stop()) {
this->cancel_timeout("move");

View File

@@ -47,14 +47,18 @@ class DemoFan : public fan::Fan, public Component {
protected:
void control(const fan::FanCall &call) override {
if (call.get_state().has_value())
this->state = *call.get_state();
if (call.get_oscillating().has_value())
this->oscillating = *call.get_oscillating();
if (call.get_speed().has_value())
this->speed = *call.get_speed();
if (call.get_direction().has_value())
this->direction = *call.get_direction();
auto state = call.get_state();
if (state.has_value())
this->state = *state;
auto oscillating = call.get_oscillating();
if (oscillating.has_value())
this->oscillating = *oscillating;
auto speed = call.get_speed();
if (speed.has_value())
this->speed = *speed;
auto direction = call.get_direction();
if (direction.has_value())
this->direction = *direction;
this->publish_state();
}

View File

@@ -8,8 +8,9 @@ namespace demo {
class DemoLock : public lock::Lock {
protected:
void control(const lock::LockCall &call) override {
auto state = *call.get_state();
this->publish_state(state);
auto state = call.get_state();
if (state.has_value())
this->publish_state(*state);
}
};

View File

@@ -26,12 +26,15 @@ class DemoValve : public valve::Valve {
protected:
void control(const valve::ValveCall &call) override {
if (call.get_position().has_value()) {
this->position = *call.get_position();
auto pos = call.get_position();
if (pos.has_value()) {
this->position = *pos;
this->publish_state();
return;
} else if (call.get_toggle().has_value()) {
if (call.get_toggle().value()) {
}
auto toggle = call.get_toggle();
if (toggle.has_value()) {
if (*toggle) {
if (this->position == valve::VALVE_OPEN) {
this->position = valve::VALVE_CLOSED;
this->publish_state();

View File

@@ -28,7 +28,7 @@ uint8_t EmmetiClimate::set_mode_() {
}
uint8_t EmmetiClimate::set_fan_speed_() {
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
return EMMETI_FAN_1;
case climate::CLIMATE_FAN_MEDIUM:

View File

@@ -37,8 +37,9 @@ void EndstopCover::control(const CoverCall &call) {
}
}
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto opt_pos = call.get_position();
if (opt_pos.has_value()) {
auto pos = *opt_pos;
if (pos == this->position) {
// already at target
} else {

View File

@@ -107,7 +107,7 @@ class ESPBTDevice {
for (auto &it : this->manufacturer_datas_) {
auto res = ESPBLEiBeacon::from_manufacturer_data(it);
if (res.has_value())
return *res;
return res;
}
return {};
}

View File

@@ -162,7 +162,8 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
// protect from refreshing too often
uint32_t now = micros();
if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
auto rate = this->max_refresh_rate_.value_or(0);
if (rate != 0 && (now - this->last_refresh_) < rate) {
// try again next loop iteration, so that this change won't get lost
this->schedule_show();
return;
@@ -301,7 +302,7 @@ void ESP32RMTLEDStripLightOutput::dump_config() {
" RGB Order: %s\n"
" Max refresh rate: %" PRIu32 "\n"
" Number of LEDs: %u",
rgb_order, *this->max_refresh_rate_, this->num_leds_);
rgb_order, this->max_refresh_rate_.value_or(0), this->num_leds_);
}
float ESP32RMTLEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }

View File

@@ -21,12 +21,13 @@ void FastLEDLightOutput::dump_config() {
"FastLED light:\n"
" Num LEDs: %u\n"
" Max refresh rate: %u",
this->num_leds_, *this->max_refresh_rate_);
this->num_leds_, this->max_refresh_rate_.value_or(0));
}
void FastLEDLightOutput::write_state(light::LightState *state) {
// protect from refreshing too often
uint32_t now = micros();
if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
uint32_t max_rate = this->max_refresh_rate_.value_or(0);
if (max_rate != 0 && (now - this->last_refresh_) < max_rate) {
// try again next loop iteration, so that this change won't get lost
this->schedule_show();
return;

View File

@@ -269,9 +269,12 @@ void FeedbackCover::control(const CoverCall &call) {
this->start_direction_(COVER_OPERATION_CLOSING);
}
}
} else if (call.get_position().has_value()) {
} else {
auto pos_opt = call.get_position();
if (!pos_opt.has_value())
return;
// go to position action
auto pos = *call.get_position();
auto pos = *pos_opt;
if (pos == this->position) {
// already at target,

View File

@@ -141,7 +141,7 @@ void FujitsuGeneralClimate::transmit_state() {
}
// Set fan
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_HIGH:
SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_HIGH);
break;

View File

@@ -180,7 +180,7 @@ uint8_t GreeClimate::operation_mode_() {
uint8_t GreeClimate::fan_speed_() {
// YX1FF has 4 fan speeds -- we treat low as quiet and turbo as high
if (this->model_ == GREE_YX1FF) {
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_QUIET:
return GREE_FAN_1;
case climate::CLIMATE_FAN_LOW:
@@ -195,7 +195,7 @@ uint8_t GreeClimate::fan_speed_() {
}
}
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
return GREE_FAN_1;
case climate::CLIMATE_FAN_MEDIUM:
@@ -235,7 +235,7 @@ uint8_t GreeClimate::temperature_() {
uint8_t GreeClimate::preset_() {
// YX1FF has sleep preset
if (this->model_ == GREE_YX1FF) {
switch (this->preset.value()) {
switch (this->preset.value_or(climate::CLIMATE_PRESET_NONE)) {
case climate::CLIMATE_PRESET_NONE:
return GREE_PRESET_NONE;
case climate::CLIMATE_PRESET_SLEEP:

View File

@@ -893,7 +893,8 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
} else {
this->preset = CLIMATE_PRESET_NONE;
}
should_publish = should_publish || (!old_preset.has_value()) || (old_preset.value() != this->preset.value());
should_publish = should_publish || (!old_preset.has_value()) ||
(old_preset.value_or(CLIMATE_PRESET_NONE) != this->preset.value_or(CLIMATE_PRESET_NONE));
}
{
// Target temperature
@@ -936,7 +937,8 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
this->fan_mode = CLIMATE_FAN_HIGH;
break;
}
should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value());
should_publish = should_publish || (!old_fan_mode.has_value()) ||
(old_fan_mode.value_or(CLIMATE_FAN_ON) != this->fan_mode.value_or(CLIMATE_FAN_ON));
}
// Display status
// should be before "Climate mode" because it is changing this->mode
@@ -1301,7 +1303,8 @@ void HonClimate::clear_control_messages_queue_() {
}
bool HonClimate::prepare_pending_action() {
switch (this->action_request_.value().action) {
auto &action_request = this->action_request_.value(); // NOLINT(bugprone-unchecked-optional-access)
switch (action_request.action) {
case ActionRequest::START_SELF_CLEAN:
if (this->control_method_ == HonControlMethod::SET_GROUP_PARAMETERS) {
uint8_t control_out_buffer[haier_protocol::MAX_FRAME_SIZE];
@@ -1315,12 +1318,12 @@ bool HonClimate::prepare_pending_action() {
out_data->ac_power = 1;
out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY;
out_data->light_status = 0;
this->action_request_.value().message = haier_protocol::HaierMessage(
action_request.message = haier_protocol::HaierMessage(
haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS,
control_out_buffer, this->real_control_packet_size_);
return true;
} else if (this->control_method_ == HonControlMethod::SET_SINGLE_PARAMETER) {
this->action_request_.value().message =
action_request.message =
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
(uint8_t) hon_protocol::DataParameters::SELF_CLEANING,
@@ -1343,7 +1346,7 @@ bool HonClimate::prepare_pending_action() {
out_data->ac_power = 1;
out_data->ac_mode = (uint8_t) hon_protocol::ConditioningMode::DRY;
out_data->light_status = 0;
this->action_request_.value().message = haier_protocol::HaierMessage(
action_request.message = haier_protocol::HaierMessage(
haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_GROUP_PARAMETERS,
control_out_buffer, this->real_control_packet_size_);
return true;

View File

@@ -402,7 +402,8 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin
} else {
this->preset = CLIMATE_PRESET_NONE;
}
should_publish = should_publish || (!old_preset.has_value()) || (old_preset.value() != this->preset.value());
should_publish = should_publish || (!old_preset.has_value()) ||
(old_preset.value_or(CLIMATE_PRESET_NONE) != this->preset.value_or(CLIMATE_PRESET_NONE));
}
{
// Target temperature
@@ -446,7 +447,8 @@ haier_protocol::HandlerError Smartair2Climate::process_status_message_(const uin
this->fan_mode = CLIMATE_FAN_HIGH;
break;
}
should_publish = should_publish || (!old_fan_mode.has_value()) || (old_fan_mode.value() != fan_mode.value());
should_publish = should_publish || (!old_fan_mode.has_value()) ||
(old_fan_mode.value_or(CLIMATE_FAN_ON) != this->fan_mode.value_or(CLIMATE_FAN_ON));
}
// Display status
// should be before "Climate mode" because it is changing this->mode

View File

@@ -49,14 +49,18 @@ void HBridgeFan::dump_config() {
}
void HBridgeFan::control(const fan::FanCall &call) {
if (call.get_state().has_value())
this->state = *call.get_state();
if (call.get_speed().has_value())
this->speed = *call.get_speed();
if (call.get_oscillating().has_value())
this->oscillating = *call.get_oscillating();
if (call.get_direction().has_value())
this->direction = *call.get_direction();
auto call_state = call.get_state();
if (call_state.has_value())
this->state = *call_state;
auto call_speed = call.get_speed();
if (call_speed.has_value())
this->speed = *call_speed;
auto call_oscillating = call.get_oscillating();
if (call_oscillating.has_value())
this->oscillating = *call_oscillating;
auto call_direction = call.get_direction();
if (call_direction.has_value())
this->direction = *call_direction;
this->apply_preset_mode_(call);
this->write_state_();

View File

@@ -171,9 +171,12 @@ void HE60rCover::control(const CoverCall &call) {
} else {
this->toggles_needed_++;
}
} else if (call.get_position().has_value()) {
} else {
auto pos_opt = call.get_position();
if (!pos_opt.has_value())
return;
// go to position action
auto pos = *call.get_position();
auto pos = *pos_opt;
// are we at the target?
if (pos == this->position) {
this->start_direction_(COVER_OPERATION_IDLE);

View File

@@ -175,7 +175,7 @@ void HitachiClimate::transmit_state() {
set_temp_(static_cast<uint8_t>(this->target_temperature));
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
set_fan_(HITACHI_AC344_FAN_LOW);
break;

View File

@@ -176,7 +176,7 @@ void HitachiClimate::transmit_state() {
set_temp_(static_cast<uint8_t>(this->target_temperature));
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
set_fan_(HITACHI_AC424_FAN_LOW);
break;

View File

@@ -11,17 +11,18 @@ static const char *const TAG = "audio";
void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) {
media_player::MediaPlayerState play_state = media_player::MEDIA_PLAYER_STATE_PLAYING;
if (call.get_announcement().has_value()) {
play_state = call.get_announcement().value() ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING
: media_player::MEDIA_PLAYER_STATE_PLAYING;
auto announcement = call.get_announcement();
if (announcement.has_value()) {
play_state = *announcement ? media_player::MEDIA_PLAYER_STATE_ANNOUNCING : media_player::MEDIA_PLAYER_STATE_PLAYING;
}
if (call.get_media_url().has_value()) {
this->current_url_ = call.get_media_url();
auto media_url = call.get_media_url();
if (media_url.has_value()) {
this->current_url_ = media_url;
if (this->i2s_state_ != I2S_STATE_STOPPED && this->audio_ != nullptr) {
if (this->audio_->isRunning()) {
this->audio_->stopSong();
}
this->audio_->connecttohost(this->current_url_.value().c_str());
this->audio_->connecttohost(media_url->c_str());
this->state = play_state;
} else {
this->start();
@@ -32,13 +33,15 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) {
this->is_announcement_ = true;
}
if (call.get_volume().has_value()) {
this->volume = call.get_volume().value();
auto vol = call.get_volume();
if (vol.has_value()) {
this->volume = *vol;
this->set_volume_(volume);
this->unmute_();
}
if (call.get_command().has_value()) {
switch (call.get_command().value()) {
auto cmd = call.get_command();
if (cmd.has_value()) {
switch (*cmd) {
case media_player::MEDIA_PLAYER_COMMAND_MUTE:
this->mute_();
break;
@@ -67,7 +70,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) {
if (this->i2s_state_ != I2S_STATE_RUNNING) {
return;
}
switch (call.get_command().value()) {
switch (*cmd) {
case media_player::MEDIA_PLAYER_COMMAND_PLAY:
if (!this->audio_->isRunning())
this->audio_->pauseResume();

View File

@@ -90,8 +90,9 @@ void Infrared::control(const InfraredCall &call) {
auto *transmit_data = transmit_call.get_data();
// Set carrier frequency
if (call.get_carrier_frequency().has_value()) {
transmit_data->set_carrier_frequency(call.get_carrier_frequency().value());
auto freq = call.get_carrier_frequency();
if (freq.has_value()) {
transmit_data->set_carrier_frequency(*freq);
}
// Set timings based on format

View File

@@ -56,7 +56,8 @@ optional<uint8_t> ledc_bit_depth_for_frequency(float frequency) {
esp_err_t configure_timer_frequency(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_channel_t chan_num,
uint8_t channel, uint8_t &bit_depth, float frequency) {
bit_depth = *ledc_bit_depth_for_frequency(frequency);
auto bit_depth_opt = ledc_bit_depth_for_frequency(frequency);
bit_depth = bit_depth_opt.value_or(0);
if (bit_depth < 1) {
ESP_LOGE(TAG, "Frequency %f can't be achieved with any bit depth", frequency);
}

View File

@@ -19,8 +19,9 @@ void Mcp4461Component::setup() {
// save WP/WL status
this->update_write_protection_status_();
for (uint8_t i = 0; i < 8; i++) {
if (this->reg_[i].initial_value.has_value()) {
uint16_t initial_state = static_cast<uint16_t>(*this->reg_[i].initial_value * 256.0f);
auto init_val = this->reg_[i].initial_value;
if (init_val.has_value()) {
uint16_t initial_state = static_cast<uint16_t>(*init_val * 256.0f);
this->write_wiper_level_(i, initial_state);
}
if (this->reg_[i].enabled) {

View File

@@ -56,20 +56,25 @@ void AirConditioner::on_status_change() {
void AirConditioner::control(const ClimateCall &call) {
dudanov::midea::ac::Control ctrl{};
if (call.get_target_temperature().has_value())
ctrl.targetTemp = call.get_target_temperature().value();
if (call.get_swing_mode().has_value())
ctrl.swingMode = Converters::to_midea_swing_mode(call.get_swing_mode().value());
if (call.get_mode().has_value())
ctrl.mode = Converters::to_midea_mode(call.get_mode().value());
if (call.get_preset().has_value()) {
ctrl.preset = Converters::to_midea_preset(call.get_preset().value());
auto target_temp_val = call.get_target_temperature();
if (target_temp_val.has_value())
ctrl.targetTemp = *target_temp_val;
auto swing_mode_val = call.get_swing_mode();
if (swing_mode_val.has_value())
ctrl.swingMode = Converters::to_midea_swing_mode(*swing_mode_val);
auto mode_val = call.get_mode();
if (mode_val.has_value())
ctrl.mode = Converters::to_midea_mode(*mode_val);
auto preset_val = call.get_preset();
if (preset_val.has_value()) {
ctrl.preset = Converters::to_midea_preset(*preset_val);
} else if (call.has_custom_preset()) {
// get_custom_preset() returns StringRef pointing to null-terminated string literals from codegen
ctrl.preset = Converters::to_midea_preset(call.get_custom_preset().c_str());
}
if (call.get_fan_mode().has_value()) {
ctrl.fanMode = Converters::to_midea_fan_mode(call.get_fan_mode().value());
auto fan_mode_val = call.get_fan_mode();
if (fan_mode_val.has_value()) {
ctrl.fanMode = Converters::to_midea_fan_mode(*fan_mode_val);
} else if (call.has_custom_fan_mode()) {
// get_custom_fan_mode() returns StringRef pointing to null-terminated string literals from codegen
ctrl.fanMode = Converters::to_midea_fan_mode(call.get_custom_fan_mode().c_str());

View File

@@ -114,15 +114,20 @@ void MideaIR::control(const climate::ClimateCall &call) {
if (call.get_mode() == climate::CLIMATE_MODE_OFF) {
this->swing_mode = climate::CLIMATE_SWING_OFF;
this->preset = climate::CLIMATE_PRESET_NONE;
} else if (call.get_swing_mode().has_value() && ((*call.get_swing_mode() == climate::CLIMATE_SWING_OFF &&
this->swing_mode == climate::CLIMATE_SWING_VERTICAL) ||
(*call.get_swing_mode() == climate::CLIMATE_SWING_VERTICAL &&
this->swing_mode == climate::CLIMATE_SWING_OFF))) {
this->swing_ = true;
} else if (call.get_preset().has_value() &&
((*call.get_preset() == climate::CLIMATE_PRESET_NONE && this->preset == climate::CLIMATE_PRESET_BOOST) ||
(*call.get_preset() == climate::CLIMATE_PRESET_BOOST && this->preset == climate::CLIMATE_PRESET_NONE))) {
this->boost_ = true;
} else {
auto swing = call.get_swing_mode();
if (swing.has_value() &&
((*swing == climate::CLIMATE_SWING_OFF && this->swing_mode == climate::CLIMATE_SWING_VERTICAL) ||
(*swing == climate::CLIMATE_SWING_VERTICAL && this->swing_mode == climate::CLIMATE_SWING_OFF))) {
this->swing_ = true;
} else {
auto preset = call.get_preset();
if (preset.has_value() &&
((*preset == climate::CLIMATE_PRESET_NONE && this->preset == climate::CLIMATE_PRESET_BOOST) ||
(*preset == climate::CLIMATE_PRESET_BOOST && this->preset == climate::CLIMATE_PRESET_NONE))) {
this->boost_ = true;
}
}
}
climate_ir::ClimateIR::control(call);
}

View File

@@ -180,7 +180,7 @@ void MitsubishiClimate::transmit_state() {
// For 5Level: Low = 1, Middle = 2, Medium = 3, High = 4
// For 4Level + Quiet: Low = 1, Middle = 2, Medium = 3, High = 4, Quiet = 5
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
remote_state[9] = 1;
break;
@@ -209,7 +209,8 @@ void MitsubishiClimate::transmit_state() {
break;
}
ESP_LOGD(TAG, "fan: %02x state: %02x", this->fan_mode.value(), remote_state[9]);
ESP_LOGD(TAG, "fan: %02x state: %02x", static_cast<uint8_t>(this->fan_mode.value_or(climate::CLIMATE_FAN_ON)),
remote_state[9]);
// Vertical Vane
switch (this->swing_mode) {
@@ -227,7 +228,7 @@ void MitsubishiClimate::transmit_state() {
ESP_LOGD(TAG, "default_vertical_direction_: %02X", this->default_vertical_direction_);
// Special modes
switch (this->preset.value()) {
switch (this->preset.value_or(climate::CLIMATE_PRESET_NONE)) {
case climate::CLIMATE_PRESET_ECO:
remote_state[6] = MITSUBISHI_MODE_COOL | MITSUBISHI_OTHERWISE;
remote_state[8] = (remote_state[8] & ~7) | MITSUBISHI_MODE_A_COOL;

View File

@@ -52,7 +52,7 @@ void ModbusSelect::control(size_t index) {
// Transform func requires string parameter for backward compatibility
auto val = (*this->write_transform_func_)(this, std::string(option), *mapval, data);
if (val.has_value()) {
mapval = *val;
mapval = val;
ESP_LOGV(TAG, "write_lambda returned mapping value %lld", *mapval);
} else {
ESP_LOGD(TAG, "Communication handled by write_lambda - exiting control");

View File

@@ -71,7 +71,7 @@ void NoblexClimate::transmit_state() {
break;
}
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
remote_state[0] |= (IRNoblexFan::IR_NOBLEX_FAN_LOW << 2);
break;

View File

@@ -26,7 +26,8 @@ class NoblexClimate : public climate_ir::ClimateIR {
void control(const climate::ClimateCall &call) override {
send_swing_cmd_ = call.get_swing_mode().has_value();
// swing resets after unit powered off
if (call.get_mode().has_value() && *call.get_mode() == climate::CLIMATE_MODE_OFF)
auto mode = call.get_mode();
if (mode.has_value() && *mode == climate::CLIMATE_MODE_OFF)
this->swing_mode = climate::CLIMATE_SWING_OFF;
climate_ir::ClimateIR::control(call);
}

View File

@@ -9,7 +9,10 @@ static const char *const TAG = "output.lock";
void OutputLock::dump_config() { LOG_LOCK("", "Output Lock", this); }
void OutputLock::control(const lock::LockCall &call) {
auto state = *call.get_state();
auto state_val = call.get_state();
if (!state_val.has_value())
return;
auto state = *state_val;
if (state == lock::LOCK_STATE_LOCKED) {
this->output_->turn_on();
} else if (state == lock::LOCK_STATE_UNLOCKED) {

View File

@@ -41,10 +41,12 @@ void PIDClimate::setup() {
}
}
void PIDClimate::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();
auto call_mode = call.get_mode();
if (call_mode.has_value())
this->mode = *call_mode;
auto call_target = call.get_target_temperature();
if (call_target.has_value())
this->target_temperature = *call_target;
// If switching to off mode, set output immediately
if (this->mode == climate::CLIMATE_MODE_OFF)

View File

@@ -26,7 +26,10 @@ void PZEM004T::loop() {
// PZEM004T packet size is 7 byte
while (this->available() >= 7) {
auto resp = *this->read_array<7>();
auto resp_opt = this->read_array<7>();
if (!resp_opt.has_value())
break;
auto resp = *resp_opt;
// packet format:
// 0: packet type
// 1-5: data

View File

@@ -69,7 +69,7 @@ optional<size_t> SelectCall::calculate_target_index_(const char *name) {
ESP_LOGW(TAG, "'%s' - No option set", name);
return {};
}
return this->index_.value();
return this->index_;
}
// SELECT_OP_NEXT or SELECT_OP_PREVIOUS

View File

@@ -81,22 +81,16 @@ class SGP4xComponent : public PollingComponent, public sensor::Sensor, public se
void set_voc_algorithm_tuning(uint16_t index_offset, uint16_t learning_time_offset_hours,
uint16_t learning_time_gain_hours, uint16_t gating_max_duration_minutes,
uint16_t std_initial, uint16_t gain_factor) {
voc_tuning_params_.value().index_offset = index_offset;
voc_tuning_params_.value().learning_time_offset_hours = learning_time_offset_hours;
voc_tuning_params_.value().learning_time_gain_hours = learning_time_gain_hours;
voc_tuning_params_.value().gating_max_duration_minutes = gating_max_duration_minutes;
voc_tuning_params_.value().std_initial = std_initial;
voc_tuning_params_.value().gain_factor = gain_factor;
this->voc_tuning_params_ = GasTuning{
index_offset, learning_time_offset_hours, learning_time_gain_hours, gating_max_duration_minutes, std_initial,
gain_factor};
}
void set_nox_algorithm_tuning(uint16_t index_offset, uint16_t learning_time_offset_hours,
uint16_t learning_time_gain_hours, uint16_t gating_max_duration_minutes,
uint16_t gain_factor) {
nox_tuning_params_.value().index_offset = index_offset;
nox_tuning_params_.value().learning_time_offset_hours = learning_time_offset_hours;
nox_tuning_params_.value().learning_time_gain_hours = learning_time_gain_hours;
nox_tuning_params_.value().gating_max_duration_minutes = gating_max_duration_minutes;
nox_tuning_params_.value().std_initial = 50;
nox_tuning_params_.value().gain_factor = gain_factor;
this->nox_tuning_params_ =
GasTuning{index_offset, learning_time_offset_hours, learning_time_gain_hours, gating_max_duration_minutes, 50,
gain_factor};
}
protected:

View File

@@ -144,7 +144,7 @@ void SpeakerMediaPlayer::watch_media_commands_() {
delete media_command.url.value();
}
if (media_command.file.has_value()) {
playlist_item.file = media_command.file.value();
playlist_item.file = media_command.file;
}
if (this->single_pipeline_() || (media_command.announce.has_value() && media_command.announce.value())) {
@@ -495,18 +495,21 @@ void SpeakerMediaPlayer::control(const media_player::MediaPlayerCall &call) {
MediaCallCommand media_command;
if (this->single_pipeline_() || (call.get_announcement().has_value() && call.get_announcement().value())) {
auto ann = call.get_announcement();
if (this->single_pipeline_() || (ann.has_value() && *ann)) {
media_command.announce = true;
} else {
media_command.announce = false;
}
if (call.get_media_url().has_value()) {
media_command.url = new std::string(
call.get_media_url().value()); // Must be manually deleted after receiving media_command from a queue
auto media_url = call.get_media_url();
if (media_url.has_value()) {
media_command.url =
new std::string(*media_url); // Must be manually deleted after receiving media_command from a queue
if (call.get_command().has_value()) {
if (call.get_command().value() == media_player::MEDIA_PLAYER_COMMAND_ENQUEUE) {
auto cmd = call.get_command();
if (cmd.has_value()) {
if (*cmd == media_player::MEDIA_PLAYER_COMMAND_ENQUEUE) {
media_command.enqueue = true;
}
}
@@ -515,18 +518,20 @@ void SpeakerMediaPlayer::control(const media_player::MediaPlayerCall &call) {
return;
}
if (call.get_volume().has_value()) {
media_command.volume = call.get_volume().value();
auto vol = call.get_volume();
if (vol.has_value()) {
media_command.volume = vol;
// Wait 0 ticks for queue to be free, volume sets aren't that important!
xQueueSend(this->media_control_command_queue_, &media_command, 0);
return;
}
if (call.get_command().has_value()) {
media_command.command = call.get_command().value();
auto cmd = call.get_command();
if (cmd.has_value()) {
media_command.command = cmd;
TickType_t ticks_to_wait = portMAX_DELAY;
if ((call.get_command().value() == media_player::MEDIA_PLAYER_COMMAND_VOLUME_UP) ||
(call.get_command().value() == media_player::MEDIA_PLAYER_COMMAND_VOLUME_DOWN)) {
if ((*cmd == media_player::MEDIA_PLAYER_COMMAND_VOLUME_UP) ||
(*cmd == media_player::MEDIA_PLAYER_COMMAND_VOLUME_DOWN)) {
ticks_to_wait = 0; // Wait 0 ticks for queue to be free, volume sets aren't that important!
}
xQueueSend(this->media_control_command_queue_, &media_command, ticks_to_wait);

View File

@@ -21,14 +21,18 @@ void SpeedFan::setup() {
void SpeedFan::dump_config() { LOG_FAN("", "Speed Fan", this); }
void SpeedFan::control(const fan::FanCall &call) {
if (call.get_state().has_value())
this->state = *call.get_state();
if (call.get_speed().has_value())
this->speed = *call.get_speed();
if (call.get_oscillating().has_value())
this->oscillating = *call.get_oscillating();
if (call.get_direction().has_value())
this->direction = *call.get_direction();
auto call_state = call.get_state();
if (call_state.has_value())
this->state = *call_state;
auto call_speed = call.get_speed();
if (call_speed.has_value())
this->speed = *call_speed;
auto call_oscillating = call.get_oscillating();
if (call_oscillating.has_value())
this->oscillating = *call_oscillating;
auto call_direction = call.get_direction();
if (call_direction.has_value())
this->direction = *call_direction;
this->apply_preset_mode_(call);
this->write_state_();

View File

@@ -44,7 +44,7 @@ SprinklerControllerSwitch::SprinklerControllerSwitch() = default;
void SprinklerControllerSwitch::loop() {
// Loop is only enabled when f_ has a value (see setup())
auto s = (*this->f_)();
auto s = (*this->f_)(); // NOLINT(bugprone-unchecked-optional-access)
if (s.has_value()) {
this->publish_state(*s);
}
@@ -89,20 +89,21 @@ void SprinklerValveOperator::loop() {
uint32_t now = App.get_loop_component_start_time();
switch (this->state_) {
case STARTING:
if ((now - *this->start_millis_) > this->start_delay_) {
if ((now - *this->start_millis_) > this->start_delay_) { // NOLINT(bugprone-unchecked-optional-access)
this->run_(); // start_delay_ has been exceeded, so ensure both valves are on and update the state
}
break;
case ACTIVE:
if ((now - *this->start_millis_) > (this->start_delay_ + this->run_duration_)) {
if ((now - *this->start_millis_) > // NOLINT(bugprone-unchecked-optional-access)
(this->start_delay_ + this->run_duration_)) {
this->stop(); // start_delay_ + run_duration_ has been exceeded, start shutting down
}
break;
case STOPPING:
if ((now - *this->stop_millis_) > this->stop_delay_) {
this->kill_(); // stop_delay_has been exceeded, ensure all valves are off
if ((now - *this->stop_millis_) > this->stop_delay_) { // NOLINT(bugprone-unchecked-optional-access)
this->kill_(); // stop_delay_has been exceeded, ensure all valves are off
}
break;
@@ -1067,7 +1068,8 @@ uint32_t Sprinkler::total_cycle_time_enabled_incomplete_valves() {
if (this->valve_is_enabled_(valve)) {
enabled_valve_count++;
if (!this->valve_cycle_complete_(valve)) {
if (!this->active_valve().has_value() || (valve != this->active_valve().value())) {
auto active = this->active_valve();
if (!active.has_value() || (valve != *active)) {
total_time_remaining += this->valve_run_duration_adjusted(valve);
incomplete_valve_count++;
} else {
@@ -1190,8 +1192,11 @@ switch_::Switch *Sprinkler::valve_switch(const size_t valve_number) {
}
switch_::Switch *Sprinkler::valve_pump_switch(const size_t valve_number) {
if (this->is_a_valid_valve(valve_number) && this->valve_[valve_number].pump_switch_index.has_value()) {
return this->pump_[this->valve_[valve_number].pump_switch_index.value()];
if (this->is_a_valid_valve(valve_number)) {
auto idx = this->valve_[valve_number].pump_switch_index;
if (idx.has_value()) {
return this->pump_[*idx];
}
}
return nullptr;
}

View File

@@ -89,7 +89,7 @@ void Tcl112Climate::transmit_state() {
// Set fan
uint8_t selected_fan;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_HIGH:
selected_fan = TCL112_FAN_HIGH;
break;

View File

@@ -257,14 +257,16 @@ void TemplateAlarmControlPanel::bypass_before_arming() {
}
void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) {
if (call.get_state()) {
if (call.get_state() == ACP_STATE_ARMED_AWAY) {
auto opt_state = call.get_state();
if (opt_state) {
auto state = *opt_state;
if (state == ACP_STATE_ARMED_AWAY) {
this->arm_(call.get_code(), ACP_STATE_ARMED_AWAY, this->arming_away_time_);
} else if (call.get_state() == ACP_STATE_ARMED_HOME) {
} else if (state == ACP_STATE_ARMED_HOME) {
this->arm_(call.get_code(), ACP_STATE_ARMED_HOME, this->arming_home_time_);
} else if (call.get_state() == ACP_STATE_ARMED_NIGHT) {
} else if (state == ACP_STATE_ARMED_NIGHT) {
this->arm_(call.get_code(), ACP_STATE_ARMED_NIGHT, this->arming_night_time_);
} else if (call.get_state() == ACP_STATE_DISARMED) {
} else if (state == ACP_STATE_DISARMED) {
if (!this->is_code_valid_(call.get_code())) {
ESP_LOGW(TAG, "Not disarming code doesn't match");
return;
@@ -274,13 +276,12 @@ void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) {
#ifdef USE_BINARY_SENSOR
this->bypassed_sensor_indicies_.clear();
#endif
} else if (call.get_state() == ACP_STATE_TRIGGERED) {
} else if (state == ACP_STATE_TRIGGERED) {
this->publish_state(ACP_STATE_TRIGGERED);
} else if (call.get_state() == ACP_STATE_PENDING) {
} else if (state == ACP_STATE_PENDING) {
this->publish_state(ACP_STATE_PENDING);
} else {
ESP_LOGE(TAG, "State not yet implemented: %s",
LOG_STR_ARG(alarm_control_panel_state_to_string(*call.get_state())));
ESP_LOGE(TAG, "State not yet implemented: %s", LOG_STR_ARG(alarm_control_panel_state_to_string(state)));
}
}
}

View File

@@ -74,8 +74,9 @@ void TemplateCover::control(const CoverCall &call) {
this->prev_command_trigger_ = &this->toggle_trigger_;
this->publish_state();
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto pos_val = call.get_position();
if (pos_val.has_value()) {
auto pos = *pos_val;
this->stop_prev_trigger_();
if (pos == COVER_OPEN) {
@@ -93,8 +94,9 @@ void TemplateCover::control(const CoverCall &call) {
}
}
if (call.get_tilt().has_value()) {
auto tilt = *call.get_tilt();
auto tilt_val = call.get_tilt();
if (tilt_val.has_value()) {
auto tilt = *tilt_val;
this->tilt_trigger_.trigger(tilt);
if (this->optimistic_) {

View File

@@ -48,46 +48,49 @@ void TemplateDate::update() {
}
void TemplateDate::control(const datetime::DateCall &call) {
bool has_year = call.get_year().has_value();
bool has_month = call.get_month().has_value();
bool has_day = call.get_day().has_value();
auto opt_year = call.get_year();
auto opt_month = call.get_month();
auto opt_day = call.get_day();
bool has_year = opt_year.has_value();
bool has_month = opt_month.has_value();
bool has_day = opt_day.has_value();
ESPTime value = {};
if (has_year)
value.year = *call.get_year();
value.year = *opt_year;
if (has_month)
value.month = *call.get_month();
value.month = *opt_month;
if (has_day)
value.day_of_month = *call.get_day();
value.day_of_month = *opt_day;
this->set_trigger_.trigger(value);
if (this->optimistic_) {
if (has_year)
this->year_ = *call.get_year();
this->year_ = *opt_year;
if (has_month)
this->month_ = *call.get_month();
this->month_ = *opt_month;
if (has_day)
this->day_ = *call.get_day();
this->day_ = *opt_day;
this->publish_state();
}
if (this->restore_value_) {
datetime::DateEntityRestoreState temp = {};
if (has_year) {
temp.year = *call.get_year();
temp.year = *opt_year;
} else {
temp.year = this->year_;
}
if (has_month) {
temp.month = *call.get_month();
temp.month = *opt_month;
} else {
temp.month = this->month_;
}
if (has_day) {
temp.day = *call.get_day();
temp.day = *opt_day;
} else {
temp.day = this->day_;
}

View File

@@ -54,79 +54,85 @@ void TemplateDateTime::update() {
}
void TemplateDateTime::control(const datetime::DateTimeCall &call) {
bool has_year = call.get_year().has_value();
bool has_month = call.get_month().has_value();
bool has_day = call.get_day().has_value();
bool has_hour = call.get_hour().has_value();
bool has_minute = call.get_minute().has_value();
bool has_second = call.get_second().has_value();
auto opt_year = call.get_year();
auto opt_month = call.get_month();
auto opt_day = call.get_day();
auto opt_hour = call.get_hour();
auto opt_minute = call.get_minute();
auto opt_second = call.get_second();
bool has_year = opt_year.has_value();
bool has_month = opt_month.has_value();
bool has_day = opt_day.has_value();
bool has_hour = opt_hour.has_value();
bool has_minute = opt_minute.has_value();
bool has_second = opt_second.has_value();
ESPTime value = {};
if (has_year)
value.year = *call.get_year();
value.year = *opt_year;
if (has_month)
value.month = *call.get_month();
value.month = *opt_month;
if (has_day)
value.day_of_month = *call.get_day();
value.day_of_month = *opt_day;
if (has_hour)
value.hour = *call.get_hour();
value.hour = *opt_hour;
if (has_minute)
value.minute = *call.get_minute();
value.minute = *opt_minute;
if (has_second)
value.second = *call.get_second();
value.second = *opt_second;
this->set_trigger_.trigger(value);
if (this->optimistic_) {
if (has_year)
this->year_ = *call.get_year();
this->year_ = *opt_year;
if (has_month)
this->month_ = *call.get_month();
this->month_ = *opt_month;
if (has_day)
this->day_ = *call.get_day();
this->day_ = *opt_day;
if (has_hour)
this->hour_ = *call.get_hour();
this->hour_ = *opt_hour;
if (has_minute)
this->minute_ = *call.get_minute();
this->minute_ = *opt_minute;
if (has_second)
this->second_ = *call.get_second();
this->second_ = *opt_second;
this->publish_state();
}
if (this->restore_value_) {
datetime::DateTimeEntityRestoreState temp = {};
if (has_year) {
temp.year = *call.get_year();
temp.year = *opt_year;
} else {
temp.year = this->year_;
}
if (has_month) {
temp.month = *call.get_month();
temp.month = *opt_month;
} else {
temp.month = this->month_;
}
if (has_day) {
temp.day = *call.get_day();
temp.day = *opt_day;
} else {
temp.day = this->day_;
}
if (has_hour) {
temp.hour = *call.get_hour();
temp.hour = *opt_hour;
} else {
temp.hour = this->hour_;
}
if (has_minute) {
temp.minute = *call.get_minute();
temp.minute = *opt_minute;
} else {
temp.minute = this->minute_;
}
if (has_second) {
temp.second = *call.get_second();
temp.second = *opt_second;
} else {
temp.second = this->second_;
}

View File

@@ -48,46 +48,49 @@ void TemplateTime::update() {
}
void TemplateTime::control(const datetime::TimeCall &call) {
bool has_hour = call.get_hour().has_value();
bool has_minute = call.get_minute().has_value();
bool has_second = call.get_second().has_value();
auto opt_hour = call.get_hour();
auto opt_minute = call.get_minute();
auto opt_second = call.get_second();
bool has_hour = opt_hour.has_value();
bool has_minute = opt_minute.has_value();
bool has_second = opt_second.has_value();
ESPTime value = {};
if (has_hour)
value.hour = *call.get_hour();
value.hour = *opt_hour;
if (has_minute)
value.minute = *call.get_minute();
value.minute = *opt_minute;
if (has_second)
value.second = *call.get_second();
value.second = *opt_second;
this->set_trigger_.trigger(value);
if (this->optimistic_) {
if (has_hour)
this->hour_ = *call.get_hour();
this->hour_ = *opt_hour;
if (has_minute)
this->minute_ = *call.get_minute();
this->minute_ = *opt_minute;
if (has_second)
this->second_ = *call.get_second();
this->second_ = *opt_second;
this->publish_state();
}
if (this->restore_value_) {
datetime::TimeEntityRestoreState temp = {};
if (has_hour) {
temp.hour = *call.get_hour();
temp.hour = *opt_hour;
} else {
temp.hour = this->hour_;
}
if (has_minute) {
temp.minute = *call.get_minute();
temp.minute = *opt_minute;
} else {
temp.minute = this->minute_;
}
if (has_second) {
temp.second = *call.get_second();
temp.second = *opt_second;
} else {
temp.second = this->second_;
}

View File

@@ -20,14 +20,18 @@ void TemplateFan::setup() {
void TemplateFan::dump_config() { LOG_FAN("", "Template Fan", this); }
void TemplateFan::control(const fan::FanCall &call) {
if (call.get_state().has_value())
this->state = *call.get_state();
if (call.get_speed().has_value() && (this->speed_count_ > 0))
this->speed = *call.get_speed();
if (call.get_oscillating().has_value() && this->has_oscillating_)
this->oscillating = *call.get_oscillating();
if (call.get_direction().has_value() && this->has_direction_)
this->direction = *call.get_direction();
auto call_state = call.get_state();
if (call_state.has_value())
this->state = *call_state;
auto call_speed = call.get_speed();
if (call_speed.has_value() && (this->speed_count_ > 0))
this->speed = *call_speed;
auto call_oscillating = call.get_oscillating();
if (call_oscillating.has_value() && this->has_oscillating_)
this->oscillating = *call_oscillating;
auto call_direction = call.get_direction();
if (call_direction.has_value() && this->has_direction_)
this->direction = *call_direction;
this->apply_preset_mode_(call);
this->publish_state();

View File

@@ -25,7 +25,10 @@ void TemplateLock::control(const lock::LockCall &call) {
this->prev_trigger_->stop_action();
}
auto state = *call.get_state();
auto opt_state = call.get_state();
if (!opt_state.has_value())
return;
auto state = *opt_state;
if (state == LOCK_STATE_LOCKED) {
this->prev_trigger_ = &this->lock_trigger_;
this->lock_trigger_.trigger();

View File

@@ -77,8 +77,9 @@ void TemplateValve::control(const ValveCall &call) {
this->prev_command_trigger_ = &this->toggle_trigger_;
this->publish_state();
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto pos_val = call.get_position();
if (pos_val.has_value()) {
auto pos = *pos_val;
this->stop_prev_trigger_();
if (pos == VALVE_OPEN) {

View File

@@ -101,9 +101,10 @@ water_heater::WaterHeaterCallInternal TemplateWaterHeater::make_call() {
}
void TemplateWaterHeater::control(const water_heater::WaterHeaterCall &call) {
if (call.get_mode().has_value()) {
auto mode_val = call.get_mode();
if (mode_val.has_value()) {
if (this->optimistic_) {
this->mode_ = *call.get_mode();
this->mode_ = *mode_val;
}
}
if (!std::isnan(call.get_target_temperature())) {
@@ -112,14 +113,16 @@ void TemplateWaterHeater::control(const water_heater::WaterHeaterCall &call) {
}
}
if (call.get_away().has_value()) {
auto away_val = call.get_away();
if (away_val.has_value()) {
if (this->optimistic_) {
this->set_state_flag_(water_heater::WATER_HEATER_STATE_AWAY, *call.get_away());
this->set_state_flag_(water_heater::WATER_HEATER_STATE_AWAY, *away_val);
}
}
if (call.get_on().has_value()) {
auto on_val = call.get_on();
if (on_val.has_value()) {
if (this->optimistic_) {
this->set_state_flag_(water_heater::WATER_HEATER_STATE_ON, *call.get_on());
this->set_state_flag_(water_heater::WATER_HEATER_STATE_ON, *on_val);
}
}

View File

@@ -84,7 +84,7 @@ void ThermostatClimate::refresh() {
this->switch_to_mode_(this->mode, false);
this->switch_to_action_(this->compute_action_(), false);
this->switch_to_supplemental_action_(this->compute_supplemental_action_());
this->switch_to_fan_mode_(this->fan_mode.value(), false);
this->switch_to_fan_mode_(this->fan_mode.value_or(climate::CLIMATE_FAN_ON), false);
this->switch_to_swing_mode_(this->swing_mode, false);
this->switch_to_humidity_control_action_(this->compute_humidity_control_action_());
this->check_humidity_change_trigger_();
@@ -211,12 +211,13 @@ void ThermostatClimate::validate_target_humidity() {
void ThermostatClimate::control(const climate::ClimateCall &call) {
bool target_temperature_high_changed = false;
if (call.get_preset().has_value()) {
auto preset = call.get_preset();
if (preset.has_value()) {
// setup_complete_ blocks modifying/resetting the temps immediately after boot
if (this->setup_complete_) {
this->change_preset_(call.get_preset().value());
this->change_preset_(*preset);
} else {
this->preset = call.get_preset().value();
this->preset = preset;
}
}
if (call.has_custom_preset()) {
@@ -229,34 +230,41 @@ void ThermostatClimate::control(const climate::ClimateCall &call) {
}
}
if (call.get_mode().has_value()) {
this->mode = call.get_mode().value();
auto mode = call.get_mode();
if (mode.has_value()) {
this->mode = *mode;
}
if (call.get_fan_mode().has_value()) {
this->fan_mode = call.get_fan_mode().value();
auto fan_mode = call.get_fan_mode();
if (fan_mode.has_value()) {
this->fan_mode = fan_mode;
}
if (call.get_swing_mode().has_value()) {
this->swing_mode = call.get_swing_mode().value();
auto swing_mode = call.get_swing_mode();
if (swing_mode.has_value()) {
this->swing_mode = *swing_mode;
}
if (this->supports_two_points_) {
if (call.get_target_temperature_low().has_value()) {
this->target_temperature_low = call.get_target_temperature_low().value();
auto target_temp_low = call.get_target_temperature_low();
if (target_temp_low.has_value()) {
this->target_temperature_low = *target_temp_low;
}
if (call.get_target_temperature_high().has_value()) {
target_temperature_high_changed = this->target_temperature_high != call.get_target_temperature_high().value();
this->target_temperature_high = call.get_target_temperature_high().value();
auto target_temp_high = call.get_target_temperature_high();
if (target_temp_high.has_value()) {
target_temperature_high_changed = this->target_temperature_high != *target_temp_high;
this->target_temperature_high = *target_temp_high;
}
// ensure the two set points are valid and adjust one of them if necessary
this->validate_target_temperatures(target_temperature_high_changed ||
(this->prev_mode_ == climate::CLIMATE_MODE_COOL));
} else {
if (call.get_target_temperature().has_value()) {
this->target_temperature = call.get_target_temperature().value();
auto target_temp = call.get_target_temperature();
if (target_temp.has_value()) {
this->target_temperature = *target_temp;
this->validate_target_temperature();
}
}
if (call.get_target_humidity().has_value()) {
this->target_humidity = call.get_target_humidity().value();
auto target_humidity = call.get_target_humidity();
if (target_humidity.has_value()) {
this->target_humidity = *target_humidity;
this->validate_target_humidity();
}
// make any changes happen
@@ -1264,9 +1272,9 @@ bool ThermostatClimate::change_preset_internal_(const ThermostatClimateTargetTem
something_changed = true;
}
if (config.fan_mode_.has_value() && (this->fan_mode != config.fan_mode_.value())) {
if (config.fan_mode_.has_value() && (this->fan_mode != config.fan_mode_)) {
ESP_LOGV(TAG, "Setting fan mode to %s", LOG_STR_ARG(climate::climate_fan_mode_to_string(*config.fan_mode_)));
this->fan_mode = *config.fan_mode_;
this->fan_mode = config.fan_mode_;
something_changed = true;
}

View File

@@ -79,8 +79,9 @@ void TimeBasedCover::control(const CoverCall &call) {
}
}
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto pos_val = call.get_position();
if (pos_val.has_value()) {
auto pos = *pos_val;
if (pos == this->position) {
// already at target
if (this->manual_control_ && (pos == COVER_OPEN || pos == COVER_CLOSED)) {

View File

@@ -66,8 +66,9 @@ void Tormatic::control(const cover::CoverCall &call) {
return;
}
if (call.get_position().has_value()) {
auto pos = call.get_position().value();
auto pos_val = call.get_position();
if (pos_val.has_value()) {
auto pos = *pos_val;
this->control_position_(pos);
return;
}

View File

@@ -502,7 +502,7 @@ void ToshibaClimate::transmit_generic_() {
}
uint8_t fan;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_QUIET:
fan = TOSHIBA_FAN_SPEED_QUIET;
break;
@@ -567,7 +567,7 @@ void ToshibaClimate::transmit_rac_pt1411hwru_() {
message[2] = RAC_PT1411HWRU_NO_FAN.code1;
message[7] = RAC_PT1411HWRU_NO_FAN.code2;
} else {
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
message[2] = RAC_PT1411HWRU_FAN_LOW.code1;
message[7] = RAC_PT1411HWRU_FAN_LOW.code2;
@@ -811,12 +811,12 @@ void ToshibaClimate::transmit_ras_2819t_() {
uint8_t temp_code = get_ras_2819t_temp_code(temperature);
// Get fan speed encoding for rc_code_1
climate::ClimateFanMode effective_fan_mode = this->fan_mode.value();
climate::ClimateFanMode effective_fan_mode = this->fan_mode.value_or(climate::CLIMATE_FAN_ON);
// Dry mode only supports AUTO fan speed
if (this->mode == climate::CLIMATE_MODE_DRY) {
effective_fan_mode = climate::CLIMATE_FAN_AUTO;
if (this->fan_mode.value() != climate::CLIMATE_FAN_AUTO) {
if (this->fan_mode.value_or(climate::CLIMATE_FAN_ON) != climate::CLIMATE_FAN_AUTO) {
ESP_LOGW(TAG, "Dry mode only supports AUTO fan speed, forcing AUTO");
}
}

View File

@@ -7,8 +7,9 @@ namespace tuya {
static const char *const TAG = "tuya.climate";
void TuyaClimate::setup() {
if (this->switch_id_.has_value()) {
this->parent_->register_listener(*this->switch_id_, [this](const TuyaDatapoint &datapoint) {
auto switch_id = this->switch_id_;
if (switch_id.has_value()) {
this->parent_->register_listener(*switch_id, [this](const TuyaDatapoint &datapoint) {
ESP_LOGV(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool));
this->mode = climate::CLIMATE_MODE_OFF;
if (datapoint.value_bool) {
@@ -32,16 +33,18 @@ void TuyaClimate::setup() {
this->cooling_state_pin_->setup();
this->cooling_state_ = this->cooling_state_pin_->digital_read();
}
if (this->active_state_id_.has_value()) {
this->parent_->register_listener(*this->active_state_id_, [this](const TuyaDatapoint &datapoint) {
auto active_state_id = this->active_state_id_;
if (active_state_id.has_value()) {
this->parent_->register_listener(*active_state_id, [this](const TuyaDatapoint &datapoint) {
ESP_LOGV(TAG, "MCU reported active state is: %u", datapoint.value_enum);
this->active_state_ = datapoint.value_enum;
this->compute_state_();
this->publish_state();
});
}
if (this->target_temperature_id_.has_value()) {
this->parent_->register_listener(*this->target_temperature_id_, [this](const TuyaDatapoint &datapoint) {
auto target_temp_id = this->target_temperature_id_;
if (target_temp_id.has_value()) {
this->parent_->register_listener(*target_temp_id, [this](const TuyaDatapoint &datapoint) {
this->manual_temperature_ = datapoint.value_int * this->target_temperature_multiplier_;
if (this->reports_fahrenheit_) {
this->manual_temperature_ = (this->manual_temperature_ - 32) * 5 / 9;
@@ -53,8 +56,9 @@ void TuyaClimate::setup() {
this->publish_state();
});
}
if (this->current_temperature_id_.has_value()) {
this->parent_->register_listener(*this->current_temperature_id_, [this](const TuyaDatapoint &datapoint) {
auto current_temp_id = this->current_temperature_id_;
if (current_temp_id.has_value()) {
this->parent_->register_listener(*current_temp_id, [this](const TuyaDatapoint &datapoint) {
this->current_temperature = datapoint.value_int * this->current_temperature_multiplier_;
if (this->reports_fahrenheit_) {
this->current_temperature = (this->current_temperature - 32) * 5 / 9;
@@ -65,8 +69,9 @@ void TuyaClimate::setup() {
this->publish_state();
});
}
if (this->eco_id_.has_value()) {
this->parent_->register_listener(*this->eco_id_, [this](const TuyaDatapoint &datapoint) {
auto eco_id = this->eco_id_;
if (eco_id.has_value()) {
this->parent_->register_listener(*eco_id, [this](const TuyaDatapoint &datapoint) {
// Whether data type is BOOL or ENUM, it will still be a 1 or a 0, so the functions below are valid in both cases
this->eco_ = datapoint.value_bool;
this->eco_type_ = datapoint.type;
@@ -76,8 +81,9 @@ void TuyaClimate::setup() {
this->publish_state();
});
}
if (this->sleep_id_.has_value()) {
this->parent_->register_listener(*this->sleep_id_, [this](const TuyaDatapoint &datapoint) {
auto sleep_id = this->sleep_id_;
if (sleep_id.has_value()) {
this->parent_->register_listener(*sleep_id, [this](const TuyaDatapoint &datapoint) {
this->sleep_ = datapoint.value_bool;
ESP_LOGV(TAG, "MCU reported sleep is: %s", ONOFF(this->sleep_));
this->compute_preset_();
@@ -85,8 +91,9 @@ void TuyaClimate::setup() {
this->publish_state();
});
}
if (this->swing_vertical_id_.has_value()) {
this->parent_->register_listener(*this->swing_vertical_id_, [this](const TuyaDatapoint &datapoint) {
auto swing_vert_id = this->swing_vertical_id_;
if (swing_vert_id.has_value()) {
this->parent_->register_listener(*swing_vert_id, [this](const TuyaDatapoint &datapoint) {
this->swing_vertical_ = datapoint.value_bool;
ESP_LOGV(TAG, "MCU reported vertical swing is: %s", ONOFF(datapoint.value_bool));
this->compute_swingmode_();
@@ -94,8 +101,9 @@ void TuyaClimate::setup() {
});
}
if (this->swing_horizontal_id_.has_value()) {
this->parent_->register_listener(*this->swing_horizontal_id_, [this](const TuyaDatapoint &datapoint) {
auto swing_horiz_id = this->swing_horizontal_id_;
if (swing_horiz_id.has_value()) {
this->parent_->register_listener(*swing_horiz_id, [this](const TuyaDatapoint &datapoint) {
this->swing_horizontal_ = datapoint.value_bool;
ESP_LOGV(TAG, "MCU reported horizontal swing is: %s", ONOFF(datapoint.value_bool));
this->compute_swingmode_();
@@ -103,8 +111,9 @@ void TuyaClimate::setup() {
});
}
if (this->fan_speed_id_.has_value()) {
this->parent_->register_listener(*this->fan_speed_id_, [this](const TuyaDatapoint &datapoint) {
auto fan_speed_id = this->fan_speed_id_;
if (fan_speed_id.has_value()) {
this->parent_->register_listener(*fan_speed_id, [this](const TuyaDatapoint &datapoint) {
ESP_LOGV(TAG, "MCU reported Fan Speed Mode is: %u", datapoint.value_enum);
this->fan_state_ = datapoint.value_enum;
this->compute_fanmode_();
@@ -139,21 +148,34 @@ void TuyaClimate::loop() {
}
void TuyaClimate::control(const climate::ClimateCall &call) {
if (call.get_mode().has_value()) {
const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF;
auto mode = call.get_mode();
if (mode.has_value()) {
const bool switch_state = *mode != climate::CLIMATE_MODE_OFF;
ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state));
this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state);
const climate::ClimateMode new_mode = *call.get_mode();
auto switch_dp_id = this->switch_id_;
if (switch_dp_id.has_value()) {
this->parent_->set_boolean_datapoint_value(*switch_dp_id, switch_state);
}
const climate::ClimateMode new_mode = *mode;
if (this->active_state_id_.has_value()) {
auto active_state_dp_id = this->active_state_id_;
if (active_state_dp_id.has_value()) {
if (new_mode == climate::CLIMATE_MODE_HEAT && this->supports_heat_) {
this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_heating_value_);
auto heating_val = this->active_state_heating_value_;
if (heating_val.has_value())
this->parent_->set_enum_datapoint_value(*active_state_dp_id, *heating_val);
} else if (new_mode == climate::CLIMATE_MODE_COOL && this->supports_cool_) {
this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_cooling_value_);
} else if (new_mode == climate::CLIMATE_MODE_DRY && this->active_state_drying_value_.has_value()) {
this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_drying_value_);
} else if (new_mode == climate::CLIMATE_MODE_FAN_ONLY && this->active_state_fanonly_value_.has_value()) {
this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_fanonly_value_);
auto cooling_val = this->active_state_cooling_value_;
if (cooling_val.has_value())
this->parent_->set_enum_datapoint_value(*active_state_dp_id, *cooling_val);
} else if (new_mode == climate::CLIMATE_MODE_DRY) {
auto drying_val = this->active_state_drying_value_;
if (drying_val.has_value())
this->parent_->set_enum_datapoint_value(*active_state_dp_id, *drying_val);
} else if (new_mode == climate::CLIMATE_MODE_FAN_ONLY) {
auto fanonly_val = this->active_state_fanonly_value_;
if (fanonly_val.has_value())
this->parent_->set_enum_datapoint_value(*active_state_dp_id, *fanonly_val);
}
} else {
ESP_LOGW(TAG, "Active state (mode) datapoint not configured");
@@ -163,31 +185,38 @@ void TuyaClimate::control(const climate::ClimateCall &call) {
control_swing_mode_(call);
control_fan_mode_(call);
if (call.get_target_temperature().has_value()) {
float target_temperature = *call.get_target_temperature();
auto target_temp = call.get_target_temperature();
if (target_temp.has_value()) {
float target_temperature = *target_temp;
if (this->reports_fahrenheit_)
target_temperature = (target_temperature * 9 / 5) + 32;
ESP_LOGV(TAG, "Setting target temperature: %.1f", target_temperature);
this->parent_->set_integer_datapoint_value(*this->target_temperature_id_,
(int) (target_temperature / this->target_temperature_multiplier_));
auto target_temp_dp_id = this->target_temperature_id_;
if (target_temp_dp_id.has_value()) {
this->parent_->set_integer_datapoint_value(*target_temp_dp_id,
(int) (target_temperature / this->target_temperature_multiplier_));
}
}
if (call.get_preset().has_value()) {
const climate::ClimatePreset preset = *call.get_preset();
if (this->eco_id_.has_value()) {
auto preset_val = call.get_preset();
if (preset_val.has_value()) {
const climate::ClimatePreset preset = *preset_val;
auto eco_dp_id = this->eco_id_;
if (eco_dp_id.has_value()) {
const bool eco = preset == climate::CLIMATE_PRESET_ECO;
ESP_LOGV(TAG, "Setting eco: %s", ONOFF(eco));
if (this->eco_type_ == TuyaDatapointType::ENUM) {
this->parent_->set_enum_datapoint_value(*this->eco_id_, eco);
this->parent_->set_enum_datapoint_value(*eco_dp_id, eco);
} else {
this->parent_->set_boolean_datapoint_value(*this->eco_id_, eco);
this->parent_->set_boolean_datapoint_value(*eco_dp_id, eco);
}
}
if (this->sleep_id_.has_value()) {
auto sleep_dp_id = this->sleep_id_;
if (sleep_dp_id.has_value()) {
const bool sleep = preset == climate::CLIMATE_PRESET_SLEEP;
ESP_LOGV(TAG, "Setting sleep: %s", ONOFF(sleep));
this->parent_->set_boolean_datapoint_value(*this->sleep_id_, sleep);
this->parent_->set_boolean_datapoint_value(*sleep_dp_id, sleep);
}
}
}
@@ -196,8 +225,9 @@ void TuyaClimate::control_swing_mode_(const climate::ClimateCall &call) {
bool vertical_swing_changed = false;
bool horizontal_swing_changed = false;
if (call.get_swing_mode().has_value()) {
const auto swing_mode = *call.get_swing_mode();
auto swing_mode_val = call.get_swing_mode();
if (swing_mode_val.has_value()) {
const auto swing_mode = *swing_mode_val;
switch (swing_mode) {
case climate::CLIMATE_SWING_OFF:
@@ -241,14 +271,16 @@ void TuyaClimate::control_swing_mode_(const climate::ClimateCall &call) {
}
}
if (vertical_swing_changed && this->swing_vertical_id_.has_value()) {
auto vert_dp_id = this->swing_vertical_id_;
if (vertical_swing_changed && vert_dp_id.has_value()) {
ESP_LOGV(TAG, "Setting vertical swing: %s", ONOFF(swing_vertical_));
this->parent_->set_boolean_datapoint_value(*this->swing_vertical_id_, swing_vertical_);
this->parent_->set_boolean_datapoint_value(*vert_dp_id, swing_vertical_);
}
if (horizontal_swing_changed && this->swing_horizontal_id_.has_value()) {
auto horiz_dp_id = this->swing_horizontal_id_;
if (horizontal_swing_changed && horiz_dp_id.has_value()) {
ESP_LOGV(TAG, "Setting horizontal swing: %s", ONOFF(swing_horizontal_));
this->parent_->set_boolean_datapoint_value(*this->swing_horizontal_id_, swing_horizontal_);
this->parent_->set_boolean_datapoint_value(*horiz_dp_id, swing_horizontal_);
}
// Publish the state after updating the swing mode
@@ -256,33 +288,35 @@ void TuyaClimate::control_swing_mode_(const climate::ClimateCall &call) {
}
void TuyaClimate::control_fan_mode_(const climate::ClimateCall &call) {
if (call.get_fan_mode().has_value()) {
climate::ClimateFanMode fan_mode = *call.get_fan_mode();
auto fan_mode_val = call.get_fan_mode();
if (fan_mode_val.has_value()) {
climate::ClimateFanMode fan_mode = *fan_mode_val;
uint8_t tuya_fan_speed;
switch (fan_mode) {
case climate::CLIMATE_FAN_LOW:
tuya_fan_speed = *fan_speed_low_value_;
tuya_fan_speed = this->fan_speed_low_value_.value_or(0);
break;
case climate::CLIMATE_FAN_MEDIUM:
tuya_fan_speed = *fan_speed_medium_value_;
tuya_fan_speed = this->fan_speed_medium_value_.value_or(0);
break;
case climate::CLIMATE_FAN_MIDDLE:
tuya_fan_speed = *fan_speed_middle_value_;
tuya_fan_speed = this->fan_speed_middle_value_.value_or(0);
break;
case climate::CLIMATE_FAN_HIGH:
tuya_fan_speed = *fan_speed_high_value_;
tuya_fan_speed = this->fan_speed_high_value_.value_or(0);
break;
case climate::CLIMATE_FAN_AUTO:
tuya_fan_speed = *fan_speed_auto_value_;
tuya_fan_speed = this->fan_speed_auto_value_.value_or(0);
break;
default:
tuya_fan_speed = 0;
break;
}
if (this->fan_speed_id_.has_value()) {
this->parent_->set_enum_datapoint_value(*this->fan_speed_id_, tuya_fan_speed);
auto fan_speed_dp_id = this->fan_speed_id_;
if (fan_speed_dp_id.has_value()) {
this->parent_->set_enum_datapoint_value(*fan_speed_dp_id, tuya_fan_speed);
}
}
}
@@ -337,31 +371,39 @@ climate::ClimateTraits TuyaClimate::traits() {
void TuyaClimate::dump_config() {
LOG_CLIMATE("", "Tuya Climate", this);
if (this->switch_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
auto switch_dp_id = this->switch_id_;
if (switch_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *switch_dp_id);
}
if (this->active_state_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Active state has datapoint ID %u", *this->active_state_id_);
auto active_state_dp_id = this->active_state_id_;
if (active_state_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Active state has datapoint ID %u", *active_state_dp_id);
}
if (this->target_temperature_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Target Temperature has datapoint ID %u", *this->target_temperature_id_);
auto target_temp_dp_id = this->target_temperature_id_;
if (target_temp_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Target Temperature has datapoint ID %u", *target_temp_dp_id);
}
if (this->current_temperature_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Current Temperature has datapoint ID %u", *this->current_temperature_id_);
auto current_temp_dp_id = this->current_temperature_id_;
if (current_temp_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Current Temperature has datapoint ID %u", *current_temp_dp_id);
}
LOG_PIN(" Heating State Pin: ", this->heating_state_pin_);
LOG_PIN(" Cooling State Pin: ", this->cooling_state_pin_);
if (this->eco_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Eco has datapoint ID %u", *this->eco_id_);
auto eco_dp_id = this->eco_id_;
if (eco_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Eco has datapoint ID %u", *eco_dp_id);
}
if (this->sleep_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Sleep has datapoint ID %u", *this->sleep_id_);
auto sleep_dp_id = this->sleep_id_;
if (sleep_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Sleep has datapoint ID %u", *sleep_dp_id);
}
if (this->swing_vertical_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Swing Vertical has datapoint ID %u", *this->swing_vertical_id_);
auto swing_vert_dp_id = this->swing_vertical_id_;
if (swing_vert_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Swing Vertical has datapoint ID %u", *swing_vert_dp_id);
}
if (this->swing_horizontal_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Swing Horizontal has datapoint ID %u", *this->swing_horizontal_id_);
auto swing_horiz_dp_id = this->swing_horizontal_id_;
if (swing_horiz_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Swing Horizontal has datapoint ID %u", *swing_horiz_dp_id);
}
}

View File

@@ -39,6 +39,9 @@ void TuyaCover::setup() {
}
});
if (!this->position_id_.has_value()) {
return;
}
uint8_t report_id = *this->position_id_;
if (this->position_report_id_.has_value()) {
// A position report datapoint is configured; listen to that instead.
@@ -60,29 +63,30 @@ void TuyaCover::control(const cover::CoverCall &call) {
if (call.get_stop()) {
if (this->control_id_.has_value()) {
this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_STOP);
} else {
} else if (this->position_id_.has_value()) {
auto pos = this->position;
pos = this->invert_position_report_ ? pos : 1.0f - pos;
auto position_int = static_cast<uint32_t>(pos * this->value_range_);
position_int = position_int + this->min_value_;
parent_->force_set_integer_datapoint_value(*this->position_id_, position_int);
this->parent_->force_set_integer_datapoint_value(*this->position_id_, position_int);
}
}
if (call.get_position().has_value()) {
auto pos = *call.get_position();
auto pos_opt = call.get_position();
if (pos_opt.has_value()) {
auto pos = *pos_opt;
if (this->control_id_.has_value() && (pos == COVER_OPEN || pos == COVER_CLOSED)) {
if (pos == COVER_OPEN) {
this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_OPEN);
} else {
this->parent_->force_set_enum_datapoint_value(*this->control_id_, COMMAND_CLOSE);
}
} else {
} else if (this->position_id_.has_value()) {
pos = this->invert_position_report_ ? pos : 1.0f - pos;
auto position_int = static_cast<uint32_t>(pos * this->value_range_);
position_int = position_int + this->min_value_;
parent_->force_set_integer_datapoint_value(*this->position_id_, position_int);
this->parent_->force_set_integer_datapoint_value(*this->position_id_, position_int);
}
}

View File

@@ -7,8 +7,9 @@ namespace tuya {
static const char *const TAG = "tuya.fan";
void TuyaFan::setup() {
if (this->speed_id_.has_value()) {
this->parent_->register_listener(*this->speed_id_, [this](const TuyaDatapoint &datapoint) {
auto speed_id = this->speed_id_;
if (speed_id.has_value()) {
this->parent_->register_listener(*speed_id, [this](const TuyaDatapoint &datapoint) {
if (datapoint.type == TuyaDatapointType::ENUM) {
ESP_LOGV(TAG, "MCU reported speed of: %d", datapoint.value_enum);
if (datapoint.value_enum >= this->speed_count_) {
@@ -25,15 +26,17 @@ void TuyaFan::setup() {
this->speed_type_ = datapoint.type;
});
}
if (this->switch_id_.has_value()) {
this->parent_->register_listener(*this->switch_id_, [this](const TuyaDatapoint &datapoint) {
auto switch_id = this->switch_id_;
if (switch_id.has_value()) {
this->parent_->register_listener(*switch_id, [this](const TuyaDatapoint &datapoint) {
ESP_LOGV(TAG, "MCU reported switch is: %s", ONOFF(datapoint.value_bool));
this->state = datapoint.value_bool;
this->publish_state();
});
}
if (this->oscillation_id_.has_value()) {
this->parent_->register_listener(*this->oscillation_id_, [this](const TuyaDatapoint &datapoint) {
auto oscillation_id = this->oscillation_id_;
if (oscillation_id.has_value()) {
this->parent_->register_listener(*oscillation_id, [this](const TuyaDatapoint &datapoint) {
// Whether data type is BOOL or ENUM, it will still be a 1 or a 0, so the functions below are valid in both
// scenarios
ESP_LOGV(TAG, "MCU reported oscillation is: %s", ONOFF(datapoint.value_bool));
@@ -43,8 +46,9 @@ void TuyaFan::setup() {
this->oscillation_type_ = datapoint.type;
});
}
if (this->direction_id_.has_value()) {
this->parent_->register_listener(*this->direction_id_, [this](const TuyaDatapoint &datapoint) {
auto direction_id = this->direction_id_;
if (direction_id.has_value()) {
this->parent_->register_listener(*direction_id, [this](const TuyaDatapoint &datapoint) {
ESP_LOGD(TAG, "MCU reported reverse direction is: %s", ONOFF(datapoint.value_bool));
this->direction = datapoint.value_bool ? fan::FanDirection::REVERSE : fan::FanDirection::FORWARD;
this->publish_state();
@@ -60,17 +64,21 @@ void TuyaFan::setup() {
void TuyaFan::dump_config() {
LOG_FAN("", "Tuya Fan", this);
if (this->speed_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Speed has datapoint ID %u", *this->speed_id_);
auto speed_dp_id = this->speed_id_;
if (speed_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Speed has datapoint ID %u", *speed_dp_id);
}
if (this->switch_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *this->switch_id_);
auto switch_dp_id = this->switch_id_;
if (switch_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Switch has datapoint ID %u", *switch_dp_id);
}
if (this->oscillation_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Oscillation has datapoint ID %u", *this->oscillation_id_);
auto oscillation_dp_id = this->oscillation_id_;
if (oscillation_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Oscillation has datapoint ID %u", *oscillation_dp_id);
}
if (this->direction_id_.has_value()) {
ESP_LOGCONFIG(TAG, " Direction has datapoint ID %u", *this->direction_id_);
auto direction_dp_id = this->direction_id_;
if (direction_dp_id.has_value()) {
ESP_LOGCONFIG(TAG, " Direction has datapoint ID %u", *direction_dp_id);
}
}
@@ -80,25 +88,41 @@ fan::FanTraits TuyaFan::get_traits() {
}
void TuyaFan::control(const fan::FanCall &call) {
if (this->switch_id_.has_value() && call.get_state().has_value()) {
this->parent_->set_boolean_datapoint_value(*this->switch_id_, *call.get_state());
}
if (this->oscillation_id_.has_value() && call.get_oscillating().has_value()) {
if (this->oscillation_type_ == TuyaDatapointType::ENUM) {
this->parent_->set_enum_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
} else if (this->oscillation_type_ == TuyaDatapointType::BOOLEAN) {
this->parent_->set_boolean_datapoint_value(*this->oscillation_id_, *call.get_oscillating());
auto switch_id = this->switch_id_;
if (switch_id.has_value()) {
auto state = call.get_state();
if (state.has_value()) {
this->parent_->set_boolean_datapoint_value(*switch_id, *state);
}
}
if (this->direction_id_.has_value() && call.get_direction().has_value()) {
bool enable = *call.get_direction() == fan::FanDirection::REVERSE;
this->parent_->set_enum_datapoint_value(*this->direction_id_, enable);
auto osc_id = this->oscillation_id_;
if (osc_id.has_value()) {
auto oscillating = call.get_oscillating();
if (oscillating.has_value()) {
if (this->oscillation_type_ == TuyaDatapointType::ENUM) {
this->parent_->set_enum_datapoint_value(*osc_id, *oscillating);
} else if (this->oscillation_type_ == TuyaDatapointType::BOOLEAN) {
this->parent_->set_boolean_datapoint_value(*osc_id, *oscillating);
}
}
}
if (this->speed_id_.has_value() && call.get_speed().has_value()) {
if (this->speed_type_ == TuyaDatapointType::ENUM) {
this->parent_->set_enum_datapoint_value(*this->speed_id_, *call.get_speed() - 1);
} else if (this->speed_type_ == TuyaDatapointType::INTEGER) {
this->parent_->set_integer_datapoint_value(*this->speed_id_, *call.get_speed());
auto dir_id = this->direction_id_;
if (dir_id.has_value()) {
auto direction = call.get_direction();
if (direction.has_value()) {
bool enable = *direction == fan::FanDirection::REVERSE;
this->parent_->set_enum_datapoint_value(*dir_id, enable);
}
}
auto spd_id = this->speed_id_;
if (spd_id.has_value()) {
auto speed = call.get_speed();
if (speed.has_value()) {
if (this->speed_type_ == TuyaDatapointType::ENUM) {
this->parent_->set_enum_datapoint_value(*spd_id, *speed - 1);
} else if (this->speed_type_ == TuyaDatapointType::INTEGER) {
this->parent_->set_integer_datapoint_value(*spd_id, *speed);
}
}
}
}

View File

@@ -57,6 +57,9 @@ void TuyaLight::setup() {
return;
}
if (!this->color_type_.has_value())
return;
float red, green, blue;
switch (*this->color_type_) {
case TuyaColorType::RGBHSV:
@@ -185,7 +188,7 @@ void TuyaLight::write_state(light::LightState *state) {
}
}
if (this->color_id_.has_value() && (brightness == 0.0f || !color_interlock_)) {
if (this->color_id_.has_value() && this->color_type_.has_value() && (brightness == 0.0f || !color_interlock_)) {
std::string color_value;
switch (*this->color_type_) {
case TuyaColorType::RGB: {

View File

@@ -42,8 +42,9 @@ climate::ClimateTraits UponorSmatrixClimate::traits() {
}
void UponorSmatrixClimate::control(const climate::ClimateCall &call) {
if (call.get_target_temperature().has_value()) {
uint16_t temp = celsius_to_raw(*call.get_target_temperature());
auto val = call.get_target_temperature();
if (val.has_value()) {
uint16_t temp = celsius_to_raw(*val);
if (this->preset == climate::CLIMATE_PRESET_ECO) {
// During ECO mode, the thermostat automatically substracts the setback value from the setpoint,
// so we need to add it here first

View File

@@ -82,7 +82,7 @@ void WhirlpoolClimate::transmit_state() {
remote_state[3] |= (uint8_t) (temp - this->temperature_min_()) << 4;
// Fan speed
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_HIGH:
remote_state[2] |= WHIRLPOOL_FAN_HIGH;
break;

View File

@@ -69,7 +69,7 @@ void Whynter::transmit_state() {
}
mode_before_ = this->mode;
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
remote_state |= FAN_LOW;
break;

View File

@@ -1094,8 +1094,9 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
}
#ifdef USE_WIFI_WPA2_EAP
if (ap.get_eap().has_value()) {
EAPAuth eap_config = ap.get_eap().value();
auto eap_opt = ap.get_eap();
if (eap_opt.has_value()) {
EAPAuth eap_config = *eap_opt;
// clang-format off
ESP_LOGV(
TAG,
@@ -1129,8 +1130,9 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
ESP_LOGV(TAG, " Channel not set");
}
#ifdef USE_WIFI_MANUAL_IP
if (ap.get_manual_ip().has_value()) {
ManualIP m = *ap.get_manual_ip();
auto manual_ip = ap.get_manual_ip();
if (manual_ip.has_value()) {
ManualIP m = *manual_ip;
char static_ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
char gateway_buf[network::IP_ADDRESS_BUFFER_SIZE];
char subnet_buf[network::IP_ADDRESS_BUFFER_SIZE];

View File

@@ -298,9 +298,10 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
// setup enterprise authentication if required
#ifdef USE_WIFI_WPA2_EAP
if (ap.get_eap().has_value()) {
auto eap_opt = ap.get_eap();
if (eap_opt.has_value()) {
// note: all certificates and keys have to be null terminated. Lengths are appended by +1 to include \0.
EAPAuth eap = ap.get_eap().value();
EAPAuth eap = *eap_opt;
ret = wifi_station_set_enterprise_identity((uint8_t *) eap.identity.c_str(), eap.identity.length());
if (ret) {
ESP_LOGV(TAG, "esp_wifi_sta_wpa2_ent_set_identity failed: %d", ret);

View File

@@ -403,9 +403,10 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
// setup enterprise authentication if required
#ifdef USE_WIFI_WPA2_EAP
if (ap.get_eap().has_value()) {
auto eap_opt = ap.get_eap();
if (eap_opt.has_value()) {
// note: all certificates and keys have to be null terminated. Lengths are appended by +1 to include \0.
EAPAuth eap = ap.get_eap().value();
EAPAuth eap = *eap_opt;
#if (ESP_IDF_VERSION_MAJOR >= 5) && (ESP_IDF_VERSION_MINOR >= 1)
err = esp_eap_client_set_identity((uint8_t *) eap.identity.c_str(), eap.identity.length());
#else

View File

@@ -120,10 +120,12 @@ void YashimaClimate::setup() {
}
void YashimaClimate::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();
auto call_mode = call.get_mode();
if (call_mode.has_value())
this->mode = *call_mode;
auto call_target = call.get_target_temperature();
if (call_target.has_value())
this->target_temperature = *call_target;
this->transmit_state_();
this->publish_state();

View File

@@ -13,7 +13,7 @@ void ZHLT01Climate::transmit_state() {
ir_message[1] = 0x00; // Timer off
// Byte 3 : Turbo mode
if (this->preset.value() == climate::CLIMATE_PRESET_BOOST) {
if (this->preset.value_or(climate::CLIMATE_PRESET_NONE) == climate::CLIMATE_PRESET_BOOST) {
ir_message[3] = AC1_FAN_TURBO;
}
@@ -47,7 +47,7 @@ void ZHLT01Climate::transmit_state() {
}
// -- Fan
switch (this->preset.value()) {
switch (this->preset.value_or(climate::CLIMATE_PRESET_NONE)) {
case climate::CLIMATE_PRESET_BOOST:
ir_message[7] |= AC1_FAN3;
break;
@@ -55,7 +55,7 @@ void ZHLT01Climate::transmit_state() {
ir_message[7] |= AC1_FAN_SILENT;
break;
default:
switch (this->fan_mode.value()) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
ir_message[7] |= AC1_FAN1;
break;

View File

@@ -248,7 +248,7 @@ void log_entity_unit_of_measurement(const char *tag, const char *prefix, const E
template<typename T> class StatefulEntityBase : public EntityBase {
public:
virtual bool has_state() const { return this->state_.has_value(); }
virtual const T &get_state() const { return this->state_.value(); }
virtual const T &get_state() const { return this->state_.value(); } // NOLINT(bugprone-unchecked-optional-access)
virtual T get_state_default(T default_value) const { return this->state_.value_or(default_value); }
void invalidate_state() { this->set_new_state({}); }

View File

@@ -1,220 +1,12 @@
#pragma once
//
// Copyright (c) 2017 Martin Moene
//
// https://github.com/martinmoene/optional-bare
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Modified by Otto Winter on 18.05.18
#include <algorithm>
#include <optional>
namespace esphome {
// type for nullopt
struct nullopt_t { // NOLINT
struct init {}; // NOLINT
nullopt_t(init /*unused*/) {}
};
// extra parenthesis to prevent the most vexing parse:
const nullopt_t nullopt((nullopt_t::init())); // NOLINT
// Simplistic optional: requires T to be default constructible, copyable.
template<typename T> class optional { // NOLINT
private:
using safe_bool = void (optional::*)() const;
public:
using value_type = T;
optional() {}
optional(nullopt_t /*unused*/) {}
optional(T const &arg) : has_value_(true), value_(arg) {} // NOLINT
template<class U> optional(optional<U> const &other) : has_value_(other.has_value()), value_(other.value()) {}
optional &operator=(nullopt_t /*unused*/) {
reset();
return *this;
}
bool operator==(optional<T> const &rhs) const {
if (has_value() && rhs.has_value())
return value() == rhs.value();
return !has_value() && !rhs.has_value();
}
template<class U> optional &operator=(optional<U> const &other) {
has_value_ = other.has_value();
value_ = other.value();
return *this;
}
void swap(optional &rhs) noexcept {
using std::swap;
if (has_value() && rhs.has_value()) {
swap(**this, *rhs);
} else if (!has_value() && rhs.has_value()) {
initialize(*rhs);
rhs.reset();
} else if (has_value() && !rhs.has_value()) {
rhs.initialize(**this);
reset();
}
}
// observers
value_type const *operator->() const { return &value_; }
value_type *operator->() { return &value_; }
value_type const &operator*() const { return value_; }
value_type &operator*() { return value_; }
operator safe_bool() const { return has_value() ? &optional::this_type_does_not_support_comparisons : nullptr; }
bool has_value() const { return has_value_; }
value_type const &value() const { return value_; }
value_type &value() { return value_; }
template<class U> value_type value_or(U const &v) const { return has_value() ? value() : static_cast<value_type>(v); }
// modifiers
void reset() { has_value_ = false; }
private:
void this_type_does_not_support_comparisons() const {} // NOLINT
template<typename V> void initialize(V const &value) { // NOLINT
value_ = value;
has_value_ = true;
}
bool has_value_{false}; // NOLINT
value_type value_; // NOLINT
};
// Relational operators
template<typename T, typename U> inline bool operator==(optional<T> const &x, optional<U> const &y) {
return bool(x) != bool(y) ? false : !bool(x) ? true : *x == *y;
}
template<typename T, typename U> inline bool operator!=(optional<T> const &x, optional<U> const &y) {
return !(x == y);
}
template<typename T, typename U> inline bool operator<(optional<T> const &x, optional<U> const &y) {
return (!y) ? false : (!x) ? true : *x < *y;
}
template<typename T, typename U> inline bool operator>(optional<T> const &x, optional<U> const &y) { return (y < x); }
template<typename T, typename U> inline bool operator<=(optional<T> const &x, optional<U> const &y) { return !(y < x); }
template<typename T, typename U> inline bool operator>=(optional<T> const &x, optional<U> const &y) { return !(x < y); }
// Comparison with nullopt
template<typename T> inline bool operator==(optional<T> const &x, nullopt_t /*unused*/) { return (!x); }
template<typename T> inline bool operator==(nullopt_t /*unused*/, optional<T> const &x) { return (!x); }
template<typename T> inline bool operator!=(optional<T> const &x, nullopt_t /*unused*/) { return bool(x); }
template<typename T> inline bool operator!=(nullopt_t /*unused*/, optional<T> const &x) { return bool(x); }
template<typename T> inline bool operator<(optional<T> const & /*unused*/, nullopt_t /*unused*/) { return false; }
template<typename T> inline bool operator<(nullopt_t /*unused*/, optional<T> const &x) { return bool(x); }
template<typename T> inline bool operator<=(optional<T> const &x, nullopt_t /*unused*/) { return (!x); }
template<typename T> inline bool operator<=(nullopt_t /*unused*/, optional<T> const & /*unused*/) { return true; }
template<typename T> inline bool operator>(optional<T> const &x, nullopt_t /*unused*/) { return bool(x); }
template<typename T> inline bool operator>(nullopt_t /*unused*/, optional<T> const & /*unused*/) { return false; }
template<typename T> inline bool operator>=(optional<T> const & /*unused*/, nullopt_t /*unused*/) { return true; }
template<typename T> inline bool operator>=(nullopt_t /*unused*/, optional<T> const &x) { return (!x); }
// Comparison with T
template<typename T, typename U> inline bool operator==(optional<T> const &x, U const &v) {
return bool(x) ? *x == v : false;
}
template<typename T, typename U> inline bool operator==(U const &v, optional<T> const &x) {
return bool(x) ? v == *x : false;
}
template<typename T, typename U> inline bool operator!=(optional<T> const &x, U const &v) {
return bool(x) ? *x != v : true;
}
template<typename T, typename U> inline bool operator!=(U const &v, optional<T> const &x) {
return bool(x) ? v != *x : true;
}
template<typename T, typename U> inline bool operator<(optional<T> const &x, U const &v) {
return bool(x) ? *x < v : true;
}
template<typename T, typename U> inline bool operator<(U const &v, optional<T> const &x) {
return bool(x) ? v < *x : false;
}
template<typename T, typename U> inline bool operator<=(optional<T> const &x, U const &v) {
return bool(x) ? *x <= v : true;
}
template<typename T, typename U> inline bool operator<=(U const &v, optional<T> const &x) {
return bool(x) ? v <= *x : false;
}
template<typename T, typename U> inline bool operator>(optional<T> const &x, U const &v) {
return bool(x) ? *x > v : false;
}
template<typename T, typename U> inline bool operator>(U const &v, optional<T> const &x) {
return bool(x) ? v > *x : true;
}
template<typename T, typename U> inline bool operator>=(optional<T> const &x, U const &v) {
return bool(x) ? *x >= v : false;
}
template<typename T, typename U> inline bool operator>=(U const &v, optional<T> const &x) {
return bool(x) ? v >= *x : true;
}
// Specialized algorithms
template<typename T> void swap(optional<T> &x, optional<T> &y) noexcept { x.swap(y); }
// Convenience function to create an optional.
template<typename T> inline optional<T> make_optional(T const &v) { return optional<T>(v); }
using std::make_optional;
using std::nullopt;
using std::nullopt_t;
using std::optional;
} // namespace esphome

View File

@@ -31,9 +31,7 @@ Component = esphome_ns.class_("Component")
ComponentPtr = Component.operator("ptr")
PollingComponent = esphome_ns.class_("PollingComponent", Component)
Application = esphome_ns.class_("Application")
# Create optional with explicit namespace to avoid ambiguity with std::optional
# The generated code will use esphome::optional instead of just optional
optional = global_ns.namespace("esphome").class_("optional")
optional = global_ns.namespace("std").class_("optional")
arduino_json_ns = global_ns.namespace("ArduinoJson")
JsonObject = arduino_json_ns.class_("JsonObject")
JsonObjectConst = arduino_json_ns.class_("JsonObjectConst")

View File

@@ -66,5 +66,20 @@ def test_text_config_lamda_is_set(generate_main):
main_cpp = generate_main("tests/component_tests/text/test_text.yaml")
# Then
assert "it_4->set_template([]() -> esphome::optional<std::string> {" in main_cpp
assert "it_4->set_template([]() -> std::optional<std::string> {" in main_cpp
assert 'return std::string{"Hello"};' in main_cpp
def test_esphome_optional_alias_works(generate_main):
"""
Test that esphome::optional alias compiles (backward compatibility)
"""
# Given
# When
main_cpp = generate_main("tests/component_tests/text/test_text.yaml")
# Then
# Codegen emits std::optional, but esphome::optional must also work
# via the using alias in esphome/core/optional.h
assert "std::optional<std::string>" in main_cpp

View File

@@ -28,9 +28,14 @@ esphome:
# Test C++ API: set_template() with stateless lambda (no captures)
# NOTE: set_template() is not intended to be a public API, but we test it to ensure it doesn't break.
- lambda: |-
id(template_sens).set_template([]() -> esphome::optional<float> {
id(template_sens).set_template([]() -> std::optional<float> {
return 123.0f;
});
# Test that esphome::optional alias still works for backward compatibility
- lambda: |-
id(template_sens).set_template([]() -> esphome::optional<float> {
return 42.0f;
});
- datetime.date.set:
id: test_date