I have an ADC sensor that publishes data to a template sensor if a relay is on (as it runs off battery, and when coming out of deep sleep it turns relay on, does its probe check and sends data to HA, then turns relay off - to conserve battery) I want the sensor to take 4 samples 2 seconds apart before publishing the average value. I’ve tried the following, but “on_value” gets triggered every 2 seconds, not when the 4 samples are complete and average taken.
# Voltage from probe, only publish if relay is on, internal only
- platform: adc
id: raw_adc
pin: GPIO3
accuracy_decimals: 4
update_interval: 2s
samples: 4
sampling_mode: avg
attenuation: 12db
unit_of_measurement: "V"
internal: True
filters:
- filter_out: nan
- skip_initial: 1
on_value:
then:
- lambda: |-
ESP_LOGI("custom", "Publishing sample if relay is ON...");
if (id(relay_switch).state)
{
id(water_volume_adc).publish_state(id(raw_adc).state);
}
And that kind of works, in that my log message “Publishing sample if relay is ON…” appears every 10 seconds. However if I turn the relay ON (via switch in HA) and it’s already say 8 seconds or so into its sample, then it publishes 2 seconds later.
I guess what may be the easiest method and is my question, is can I enable or disable a GPIO input “via esphome” whilst the ESP32 is running? EG: so psuedo code would be:
come out of deep sleep
turn on relay
only then, enable GPIO and start sampling data
10 seconds later (avg of 5 samples) publish data to HA
You are asking to do things that are well outside the norm of what esphome is good at, so it will likely be very hard to do exactly what you want.
If I needed to do this, I would create a platformio project to do exactly what I wanted. Even if I didn’t have some experience with platformio, it would likely still be easier.
What you are asking for seems simple, and it is when you are controlling everything. Esphome makes it easy to do many things. This just isn’t one of them. There might be a way. Just like you can mow your lawn with scissors, how good an idea it is depends on how big your lawn is and how much time you have.
You seem to be missing some of your yaml. I assume the one called water_volume_adc is the adc sensor?
Try this - I haven’t tested it:
create a new template sensor that simply copies the value of the sensor above. Make sure the old ADC sensor is internal: true
when you turn the relay on (I assume somewhere else in your yaml?) wait 10 secs then publish the template sensor with the sensor.template.publish action.
It would be easier if we could see your complete yaml.
Further to this, I added a bit of validation and tested with different timings, specifically to ensure the sensor does not take a sample probe reading when the relay (and therefore probe) is turned off (eg: 0V from probe) To allow some probe “start up time” I changed settings to take 3 samples at 2 seconds apart (6 seconds), then changed the switch delay to 20s between on and off to compensate for the 3 x 6 second readings (18 seconds total). Deep sleep awake time is 21s. So it effectively waits for 3 data samples to be taken from the probe 2 seconds apart 3 times, but only uses the last one to avoid any 0V issues. It also does a quick check to ensure positive voltage is received, filters out nan also, and checks to ensure wifi is still connected before attempting to send (in case it drops off whilst it’s waiting for samples) Seems to work nicely!
- platform: adc
id: raw_adc
pin: GPIO3
accuracy_decimals: 4
update_interval: 2s
samples: 3
sampling_mode: avg
attenuation: 12db
unit_of_measurement: "V"
internal: True
filters:
- filter_out: nan
- skip_initial: 1
- sliding_window_moving_average:
window_size: 3
send_every: 3
on_value:
- logger.log:
format: "Sample received %.5f"
args: [ 'id(raw_adc).state' ]
# Accept voltage from ADC, publish to water volume percent
- platform: template
name: "Water Volume ADC"
id: water_volume_adc
accuracy_decimals: 4
unit_of_measurement: "V"
update_interval: never
filters:
- filter_out: nan
- filter_out: 0
- lambda: |-
if (id(relay_switch) && !(isnan(x)))
{
ESP_LOGI("custom", "Updating Water Volume ADC");
id(water_volume_percent).publish_state(x);
return x;
}
else
{
return {};
}
# Calculate water volume from ADC, compensate for small lowest voltage
- platform: template
name: "Water Volume %"
unit_of_measurement: "%"
id: water_volume_percent
update_interval: never
filters:
- filter_out: nan
- lambda: |-
ESP_LOGI("custom", "Updating Water Volume %%");
auto y = ((x - 0.1) / 3.2) * 100.0;
if (y < 0) { y = 0; }
return y;
# Read from sensor when turned on
switch:
- platform: gpio
name: "Sample Water Level"
id: relay_switch
pin:
number: GPIO16
inverted: true
mode:
output: True
open_drain: True
restore_mode: ALWAYS_OFF
on_turn_on:
- deep_sleep.prevent: deep_sleep_esp
- logger.log: "Relay Switch turned ON, reading sensor"
- delay: 20s
- if:
condition:
lambda: "return (id(raw_adc).state > 0);"
then:
- lambda: |-
if (id(wifi_connection).is_connected())
{
float y = id(raw_adc).state;
id(water_volume_adc).publish_state(id(raw_adc).state);
}
- switch.turn_off: relay_switch
on_turn_off:
- logger.log: "Relay Switch turned OFF"
- switch.turn_off: relay_switch
- if:
condition:
lambda: "return !id(block_sleep);"
then:
- deep_sleep.allow: deep_sleep_esp