Select - disable or set back to old value in script

I am trying to make my own device and got to a problem where i try to find a solution, but cant find anything that helps.

I want to have a select input, where 2 options for the mode exist, “Automatic” and “Manual”. If in Automatic mode and its inactive, the change to Manual should be possible. If in Manual mode and its inactive, the change to Automatic should be possible. But, when a manual activity is active, the change should be prevented,s ame for Automatic, change should be prevented when Automatic is active.

What i tried:
script which is activated on_value. In that script the value is checked, if its Manual and any automatic is active, switch back to Automatic, same the other way around.

Other aproach was a second mode selector, one i call “set_mode” and the other one “running_mode”. The running_mode counts for activating manual activity or also automatic activity. On value change the script checks if they are different, if so, then either switching the running mode to the value of set mode or switching the set mode back.

A Part of the second aproach works, i can change the running_mode from the script, but i can not change the select value from the set_mode. This is wired, as these are the identical values.

The part of the code for the mode:

select:
  - platform: template
    name: "Set Mode"
    id: set_mode
    options:
      - "Automatic"
      - "Manual"
    initial_option: "Automatic"
    optimistic: True
    on_value: 
      then:
        - script.execute:
            id: check_mode
  - platform: template
    name: "Running Mode"
    id: running_mode
    options:
      - "Automatic"
      - "Manual"
    initial_option: "Automatic"
    optimistic: True

script:
  - id: check_mode
    then:
      lambda: !lambda |-
        auto set_mode_state = id(set_mode).state.c_str();
        auto running_mode_state = id(running_mode).state.c_str();
        ESP_LOGD("CHECK-MODE", "New Mode: %s", set_mode_state);
        ESP_LOGD("CHECK-MODE", "Running Mode: %s", running_mode_state);
        if (strcmp(set_mode_state, running_mode_state) != 0) {
          // ---> running_mode != set_mode
          if (strcmp(set_mode_state, "Manual") == 0) {
            // ---> running_mode = Automatic
            // ---> set_mode = Manual
            ESP_LOGD("CHECK-MODE", "New Mode: %s", set_mode_state);
            if ((id(irrigation_area_1).is_running() == 1) or (id(irrigation_area_2).is_running() == 1)) {
              ESP_LOGD("CHECK-MODE", "Automatic irrigation running, cant switch mode");
              // ---> need to set "set_mode" back to Automatic
              auto call = id(set_mode).make_call();
              call.set_option("Automatic");
              call.perform();
            } else{
              ESP_LOGD("CHECK-MODE", "No automatic irrigation running");
              // ---> need to set "running_mode" to Manual
              //id(running_mode).publish_state("Manual");
              auto call = id(running_mode).make_call();
              call.set_option("Manual");
              call.perform();
            }
          } else {
            // ---> running_mode = Manual
            // ---> set_mode = Automatic
            ESP_LOGD("CHECK-MODE", "New Mode: %s", set_mode_state);
            if ((id(relay_zone_1).state == 0) and (id(relay_zone_2).state == 0) and (id(relay_zone_3).state == 0)  and (id(relay_zone_4).state == 0) and (id(relay_zone_5).state == 0) and (id(relay_zone_6).state == 0) and (id(relay_zone_7).state == 0)  and (id(relay_zone_8).state == 0)) {
              ESP_LOGD("CHECK-MODE", "No manual irrigation running, switching mode");
              // --> neet to set running_mode to Automatic
              //id(running_mode).publish_state("Automatic");
              auto call = id(running_mode).make_call();
              call.set_option("Automatic");
              call.perform();
            } else {
              ESP_LOGD("CHECK-MODE", "Manual irrigation running, cant switch mode");
              // ---> need to set "set_mode" back to Manual
              //id(set_mode).publish_state("Manual");
              auto call = id(set_mode).make_call();
              call.set_option("Manual");
              call.perform();
            }
          }
        } else {
          ESP_LOGD("CHECK-MODE", "Mode did not change");
        }

There are some debug messages where i tried to see whats happening. I see in the log, that the set_mode should be set back to Manual or Automatic, but it doenst change.
Could the reason be, that the trigger is from set_mode and that way it can not be changed?

Another aproach would be to disable changes of “set_mode”, but i couldnt find anything.

Maybe someone can give me thi right direction to find the solution. I am working with ESPHome very short time and it could be the solution what i need.

I got lost trying to understand.

Wouldn’t it be more simple to use set_action with a condition if is.running or not…

I think i tried something which was really not needed.

I hope i got it right:
optimistic set to false
and set_action will change the value and if no set_action is reached (e.g. no else statement) the selction will stay at the previous value?

If i understood the logic right, then this could be the solution.

Thanks for the hint.

Optimistic is little bit confusing here as well, but you have two options, either set it true and swap back the selection with set_action if is.runnin is true. Or set it false and don’t change the option.

Thanks, this seems to do what i need, at least for a swtich, but for select its not yet working.

At least for a switch it works. Only allowed to be switched on, when mode is set to manual. If tried to be switched on when Automatic mode is active, it also switches back to off.

For the select template i tried to implement the same, but there i see also in logs, that the select publish state is executed (at least the log messages show that the right if branch is executed). But when i try to switch to Automatic and the switch is on, which is not allowed to be on for the mode change, then the publish of the new mode is not done. I also tried to publish the old mode (x.c_str() vs. id(set_mode).state.c_str()). But it also doesnt change back like the switch.

Code of working switch:

switch:
  - platform: template
    name: "Irrigation Zone 1"
    id: irrigation_zone_1
    optimistic: False
    turn_on_action:
      if:
        condition:
          - lambda: return (strcmp(id(set_mode).state.c_str(), "Manual") == 0);
        then:
          - lambda: id(irrigation_zone_1).publish_state(true);
    turn_off_action:
      if:
        condition:
          - lambda: return (strcmp(id(set_mode).state.c_str(), "Manual") == 0);
        then:
          - lambda: id(irrigation_zone_1).publish_state(false);

Code of not working select:

select:
  - platform: template
    name: "Set Mode"
    id: set_mode
    options:
      - "Automatic"
      - "Manual"
    initial_option: "Automatic"
    #optimistic: False
    set_action:
      - lambda: return ESP_LOGI("set_mode", "Selected state is '%s'", id(set_mode).state.c_str()); 
      - lambda: return ESP_LOGI("set_mode", "Selected state is '%s'", x.c_str()); 
      - if:
          condition:
            - lambda: return (strcmp(x.c_str(), "Manual") == 0);
          then:
            - lambda: return ESP_LOGI("set_mode", "Manual");
            - if:
                condition: 
                  - script.is_running: irrigation_area_1
                then:
                  - lambda: |-
                      ESP_LOGI("set_mode", "DONT publish state '%s'", x.c_str());
                      ESP_LOGI("set_mode", "Publish old state state '%s'", id(set_mode).state.c_str());
                      id(set_mode).publish_state(id(set_mode).state.c_str());
                else:
                  - lambda: |-
                      ESP_LOGI("set_mode", "publish state '%s'", x.c_str());
                      ESP_LOGI("set_mode", "has option '%s': %i", x.c_str(), id(set_mode).has_option(x.c_str()));
                      id(set_mode).publish_state(x.c_str());
          else:
            - lambda: return ESP_LOGI("set_mode", "Automatic");
            - if:
                condition:
                  - switch.is_on: irrigation_zone_1
                then:
                  - lambda: |-
                      ESP_LOGI("set_mode", "DONT publish state '%s'", x.c_str());
                      ESP_LOGI("set_mode", "Publish old state state '%s'", id(set_mode).state.c_str());
                      id(set_mode).publish_state(id(set_mode).state.c_str());
                else:
                  - lambda: |-
                      ESP_LOGI("set_mode", "publish state '%s'", x.c_str());
                      ESP_LOGI("set_mode", "has option '%s': %i", x.c_str(), id(set_mode).has_option(x.c_str()));
                      id(set_mode).publish_state(x.c_str());

Is it working as inteded, that the new state is shown in Home Assistant?
Or am i missing something?

Hmmm, maybe its about the user interface?

I just checked how the Web Interface is reacting and there the state does not change if the change is not allowed, the only irritating part is, that the Home Assisting User Interface of the Device does not switch back.
From the Web Interface, i assume that a read back from an Automation might show the correct behaviour

Can someone confirm this?

Publishing old state should not be required, i added this to try if it would switch back with this command.

I’m not sure about HA part and can’t even test it now.
You could try optimistic:true