Problems with text_sensor mqtt_subscribe (pool-monitor PH tds, temp)

As announced, here is the solution to my problem.
It still feels like a workaround but after checking all (found) sources, this seems to be the only solution.

First, there was the obvious mistake of not setting the workmode in HA to retain. By this change the monitor gets the setting even if it was offline at the point where it was changed.

mqtt:

  select:

    command_topic: pool-monitor/workmode

    name: "workmode"

    retain: true

    options:

      - "ota"

      - "15 min"

      - "60 min"

      - "120 min"

Now to the bigger customization, the ESP doesn’t store the MQTT values itself, so I had to make a global in which I store the respective setting, for optimization I set it to a representative int which is handled in the on_message of the mqtt client.

By setting the global to restore_value: yes, the problem was solved.
There are also other customizations in the version (batterlevel etc.)

esphome:

  name: pool-monitor

  friendly_name: pool-monitor

  on_boot:

    - priority: 601

      then:

        - output.turn_on: gpio_temp #enable temp sensor

        - output.turn_off: gpio_ph

        - output.turn_off: gpio_tds

    - priority: -300

      then:

        - script.execute: check_stuff

       

  on_shutdown:

    priority: 710

    then:

      - output.turn_off: gpio_temp

     

esp32:

  board: esp32dev

  framework:

    type: arduino

deep_sleep:

  id: deep_sleep_control

  sleep_duration: 15min #We override this on call

globals:

  - id: delay_int

    type: int

    restore_value: no

    initial_value: '40'

  - id: loopcount

    type: int

    restore_value: no

    initial_value: '0'

  - id: loops

    type: int

    restore_value: no

    initial_value: '0'

  - id: phflex_done

    type: int

    restore_value: no

    initial_value: '0'

  - id: tds_done

    type: int

    restore_value: no

    initial_value: '0'

  - id: temp_done

    type: int

    restore_value: no

    initial_value: '0'

  - id: workmode

    type: int

    restore_value: yes

    initial_value: '0'

    # 0 ==> ota

    # 1 ==> 15 min

    # 2 ==> 60 min

    # 3 ==> 120 min

  - id: tds_offset

    type: float

    restore_value: no

    initial_value: '0'

logger:

#  baud_rate: 0

#  level: NONE

 

# Enable Home Assistant API

#api:

#  encryption:

#    key: "removed"

ota:

  password: "removed"

mqtt:

  id: mqtt_cli

  broker: !secret mqtthost

  port: 1883

  username: !secret mqttuser

  password: !secret mqttpassword

  birth_message:

  will_message:

  on_message:

    - topic: pool-monitor/workmode

      payload: 'ota'

      then:

        - logger.log: 'setting ota Mode'

        - lambda: |-  

            id(workmode) = 0;

    - topic: pool-monitor/workmode

      payload: '15 min'

      then:

        - logger.log: 'setting 15 min Mode'

        - lambda: |-  

            id(workmode) = 1;

    - topic: pool-monitor/workmode

      payload: '60 min'

      then:

        - logger.log: 'setting 60 min Mode'

        - lambda: |-  

            id(workmode) = 2;

    - topic: pool-monitor/workmode

      payload: '120 min'

      then:

        - logger.log: 'setting 120 min Mode'

        - lambda: |-  

            id(workmode) = 3;

wifi:

  ssid: !secret wifi_ssid

  password: !secret wifi_password

  power_save_mode: LIGHT

  fast_connect: true

  manual_ip:

    static_ip: removed

    gateway: removed

    subnet: removed

    dns1: removed

  # Enable fallback hotspot (captive portal) in case wifi connection fails

  ap:

    ssid: "Pool-Monitor Fallback Hotspot"

    password: "removed"

output:

  - platform: gpio

    pin: GPIO18

    id: gpio_temp

  - platform: gpio

    pin: GPIO17

    id: gpio_ph

  - platform: gpio

    pin: GPIO19

    id: gpio_tds

dallas:

  - pin: GPIO5

    update_interval: never

    id: dallashub

text_sensor:

  - platform: mqtt_subscribe

    name: "current workmode"

    id: mqtt_workmode

    topic: pool-monitor/workmode

  - platform: template

    name: "Last refresh"

    id: "refresher"

    lambda: |-

      char str[17];

      time_t currTime = id(homeassistant_time).now().timestamp;

      strftime(str, sizeof(str), "%Y-%m-%d %H:%M", localtime(&currTime));

      return  { str };

    update_interval: never

sensor:

  - platform: adc

    id: batt_voltage

    pin: GPIO33

    attenuation: auto

    name: Battery Voltage

    update_interval: 3s

    accuracy_decimals: 2

    filters:

      - multiply: 2.03

      - median:

          window_size: 10

          send_every: 4

          send_first_at: 3

      - delta: 0.1 #Only send values to HA if they change

#Convert the Voltage to a battery  level (%)

  - platform: copy

    source_id: batt_voltage

    id: solar_plant_batt_level

    icon: "mdi:battery"

    name:  Battery Level

    unit_of_measurement: '%'

    accuracy_decimals: 2

    filters:

      lambda: |-

          float voltage = x;

          float  percentage = 2808.3808 * pow(voltage, 4) - 43560.9157 * pow(voltage, 3) + 252848.5888 * pow(voltage, 2) - 650767.4615 * voltage + 626532.5703;

          if (voltage > 4.19) {

                  percentage = 100;

                } else {

                  if (voltage <= 3.50) percentage = 0;

                }

          return percentage;

  - platform: dallas

    address: 0x203c3ce3818e3628

    id: pool_temperature

    name: "Pool Temperature"

    device_class: temperature

    filters:

      - offset: -1.4

    on_value:

      lambda: |-

        id(temp_done)++;

# Raw TDS Reading

  - platform: adc

    pin: GPIO32

    name: "TDS 01 Raw"

    id: tds01_raw

    #attenuation: 6db

    update_interval: never

    unit_of_measurement: "v"

    accuracy_decimals: 3

    internal: true

# Temperature Compensated Voltage

  - platform: template

    name: "TDS 01 TCV"

    id: temp01_comp_v

    unit_of_measurement: 'v'

    accuracy_decimals: 3

    lambda: |-

      return (((id(tds01_raw).state) - id(tds_offset)) / (1 + (0.02 * ((id(pool_temperature).state) - 25.0))));

    update_interval: never

# Temperature Compensated TDS

  - platform: template

    name: "TDS-01"

    id: tds01_55g

    icon: "hass:water-opacity"

    unit_of_measurement: 'PPM'

    accuracy_decimals: 0

    update_interval: never  

    lambda: |-

      float voltage = id(temp01_comp_v).state;

      return (133.42 / voltage * voltage * voltage - 255.86 * voltage * voltage + 857.39* voltage)*0.5;

    on_value:

      lambda: |-

        id(tds_done)++;

  - platform: copy

    source_id: phflex

    id: ph_sensor

    icon: "mdi:flask"

    name:  pH Sensor

    unit_of_measurement: 'pH'

    accuracy_decimals: 2

    filters:

      - calibrate_linear:

          - 2.37 -> 4

          - 2.15 -> 6.86

      - delta: 0.1      

  - platform: adc

    pin: GPIO35

    name: "Flex ph"

    id: phflex

    attenuation: auto

    update_interval: never

    accuracy_decimals: 3

    filters:

      - median:

          window_size: 10

          send_every: 4

          send_first_at: 3

    on_value:

      lambda: |-

        id(phflex_done)++;

time:

  - platform: sntp

    id: homeassistant_time

    timezone: Europe/Amsterdam

script:

  - id: check_stuff

    then:

      - while:

          condition:

            lambda: return (id(workmode) == 0) || (id(loops) >= id(loopcount));

          then:

          - logger.log: 'Updating Sensors'

          - lambda: |-  #reseting counters

              id(phflex_done) = 0;

              id(tds_done) = 0;

              id(temp_done) = 0;

          - while:

                condition:

                  lambda: return (id(temp_done) <= 1);

                then:

                - delay: 1s

                - lambda: |-

                    id(dallashub).update();

          - output.turn_on: gpio_ph #enablining the ph sensor

          - delay: 60s #sensor needs time to stabilize

          - while:

              condition:

                lambda: return (id(phflex_done) <= 3);

              then:

              - delay: 2s

              - lambda: |-

                  id(phflex).update();

          - output.turn_off: gpio_ph #disabling the ph sensor

          - output.turn_on: gpio_tds #enablining the tds sensor

          - delay: 3s #sensor needs time to stabilize

          - while:

              condition:

                lambda: return (id(tds_done) <= 2);

              then:

              - delay: 1s

              - lambda: |-

                  id(tds01_raw).update();

                  id(temp01_comp_v).update();

                  id(tds01_55g).update();

          - output.turn_off: gpio_tds #disabling the tds sensor

          - logger.log: 'Updating Sensors done'

          - lambda: |-

              id(refresher).update();

          - lambda: |-          

              id(loopcount)++;

          - delay: 1s #time to Update the Mqtt topics

      - if:

          # 15 min

          condition:

            lambda: return  id(workmode) == 1;

          then:

          - lambda: |

                                              id(delay_int) = 900;

          - logger.log: 'Delay set to 15 min'

      - if:

          # 60 min

          condition:

            lambda: return  id(workmode) == 2;

          then:

          - lambda: |

                                              id(delay_int) = 3600;

          - logger.log: 'Delay set to 60 min'

      - if:

          # 120 min

          condition:

            lambda: return  id(workmode) == 3;

          then:

          - lambda: |

                                              id(delay_int) = 7200;

          - logger.log: 'Delay set to 120 min'

      - lambda: |

          auto now = id(homeassistant_time).now().timestamp;

          auto timefuture = now + id(delay_int);

          timefuture -= (timefuture % 60);

          ESP_LOGI("UGH", "Next target runtime: %d", timefuture);

          id(delay_int) = timefuture - now ;                      

      - logger.log: 'Entering sleep'

      - deep_sleep.enter:

          id: deep_sleep_control

          sleep_duration: !lambda return id(delay_int) * 1000;   #lambdas should return value as ms

captive_portal: