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: