Control power to sensor

Hi Everyone!

First time here and been searching for an answer to this for a while, hoping someone may have already done it?

I have an ESP32 setup with a resistance water level board, in order to preserve the copper traces, I want to be able to provide power to the sensor, read the value and then turn off the power.

I’d previously done this with my own firmware, but wanted to try and integrate it with HA. I don’t seem to be able to find a way to turn a GPIO pin on (the one providing power to the sensor) prior to the sensor being read.

Does anyone have any ideas on how this could be achieved?

Best Regards and Thank you!
Chris

1 Like

I’d do most of this within ESPHome.

Define the power GPIO as a GPIO output and the sensor as a resistance sensor with internal: true in ESPHome. Also define a template sensor which is what will be exported to HA. This is to ensure that you never accidentally send “unknown” or wrong values to HA from when the real sensor is not powered up.

Then write a time-based automation to turn on the output, update the template sensor with the value of the real sensor, and turn off the output.

The only HA interaction is then the sensor value itself, which should just appear.

Thanks Troon!

Forgive me if this is a stupid question, but how do you grab the value of the sensor from the template sensor?

This is what I’ve tried so far (I’m 2 days old into HA, so forgive me if it’s a dumb question) But while it produces no errors, it won’t compile.

Best Regards
Chris

sensor:
  - platform: resistance
    sensor: wl_sensor
    configuration: DOWNSTREAM
    resistor: 5.6kOhm
    name: "Water Level"
    id: water_level
    internal: true

  - platform: dht
    model: DHT11
    pin: 2
    temperature:
      name: "Outside temperature"
    humidity:
      name: "Outside humidity"
    update_interval: 20s

  - platform: adc
    id: wl_sensor
    pin: 36
  
  - platform: template
    name: "Water Level"
    lambda: |-
      if (id(ws_power).state) {
        return id(wl_sensor).value;
      }
    update_interval: 20s

output:
  - platform: gpio
    pin: 15
    id: ws_power

I tried to compile it, pasted into the body of one of my projects. With a couple of pin-related alterations for my board, I got:

src/main.cpp: In lambda function:
src/main.cpp:242:21: error: 'class esphome::gpio::GPIOBinaryOutput' has no member named 'state'
       if (ws_power->state) {
                     ^
src/main.cpp:243:27: error: 'class esphome::adc::ADCSensor' has no member named 'value'
         return wl_sensor->value;

So there doesn’t seem to be a way to check the status of an output, unless you connect it to another input and read that; and the adc should be read with .state not .value.

Also, I’d have thought the template sensor would want to return water_level's state rather than wl_sensor?

Hi, did you get anyware ? I’m looking for a solution to the same problem.
Arduino solves it nicely but i can’t find out how to do the same with esphome.

I would suggest doing it like this:

sensor:
  - platform: adc
    pin: A0
    accuracy_decimals: 4
    icon: "mdi:water-percent"
    id: rainsensor
    name: "Rainsensor Garden"

interval:
  - interval: 1min
    then:
      - output.turn_on: rs_power   
      - delay: 500ms
      - component.update: rainsensor
      - output.turn_off: rs_power 

output:
  - platform: gpio
    pin: D4
    id: rs_power  

The rainsensor is connected to D4 and A0.

EDIT: Forget the above. this won’t work, as HA polls the state from the rainsensor even if it is not powered. I thought i could circumvent this by calling component.update: rainsensor. This works, but after the 60s poll period of HA is due it fetches the value from rainsensor again but then it’s zero. So the value is continously jumping from “rain value” to “dry value”.

I made a new attempt which is working now:

sensor:
  - platform: adc
    pin: A0
    id: regensensor
    internal: true
    filters:
      - calibrate_linear:
          # Map 0.0 (from sensor) to 0.0 (true value)
          - 0.0 -> 0.0
          - 1.0 -> 100.0
  - platform: template
    name: "Regensensor Garten"
    id: regensensor_garten
    accuracy_decimals: 1
    unit_of_measurement: "%"
    icon: "mdi:water-percent"    

interval:
  - interval: 60s
    then:
      - output.turn_on: rs_power
      - delay: 500ms
      - component.update: regensensor
      - sensor.template.publish:
          id: regensensor_garten
          state: !lambda |-
            return id(regensensor).state;      
      - delay: 200ms
      - output.turn_off: rs_power
      
 
output:
  - platform: gpio
    pin: D1
    id: rs_power
 

The Rainsensor is connected to D1 and A0.

3 Likes

Thanks Kai!

This is also what should be used with Soil Sensors! You can power them using a GPIO pin to avoid corrosion with pretty much this exact code! Thanks for posting a working version. I was going nowhere and this is great.

There is no need for a template. Just remember to disable sensor updates with “update_interval: never”

  - platform: adc
    pin: A0
    name: "${upper_devicename} Soil Moisture"
    unit_of_measurement: "%"
    icon: "mdi:water-percent"
    id: soilsensor
    update_interval: never
    expire_after: 1300s
    filters:
    - calibrate_linear:
        - 0.57 -> 0.00
        - 0.28 -> 100.00
    - lambda: |
        if (x < 0) return 0; 
        else if (x > 100) return 100;
        else return (x); 
      # Find a way to report 0V as error
    accuracy_decimals: 0
   
output:
  - platform: gpio
    pin: D6
    id: soil_power

interval:
  - interval: 600s
    then:
      - output.turn_on: soil_power
      - delay: 500ms
      - component.update: soilsensor
      - delay: 200ms
      - output.turn_off: soil_power
2 Likes

thanks a tonne @Pzipp and @Kaibob2. you guys are geniuses.

was able to get a basic water level sensor working (50 cents!!) using these configs:

sensor:
  - platform: adc
    pin: GPIO36
    name: "Water Sensor"
    unit_of_measurement: "ml"
    icon: "mdi:water-percent"
    id: watersensor
    update_interval: never
    filters:
    - calibrate_polynomial:
        degree: 3
        datapoints:
          - 0 -> 0
          - 0.15 -> 5
          - 0.2 -> 10
          - 0.25 -> 15
          - 0.3 -> 20
          - 0.32 -> 25
          - 0.35 -> 30
    - lambda: |
        if (x < 0) return 0; 
        else if (x > 0.35) return 30;
        else return (x); 
    # Find a way to report 0V as error
    accuracy_decimals: 1
   
output:
  - platform: gpio
    pin: GPIO23
    id: ws_power

interval:
  - interval: 2s
    then:
      - output.turn_on: ws_power
      - delay: 500ms
      - component.update: watersensor
      - delay: 200ms
      - output.turn_off: ws_power

calibrated by taking a beaker, measuring the voltage at 5ml, 10ml, 15ml, 20ml, 25ml, 30ml respectively and then using https://mycurvefit.com/ to figure out it needs a cubic regression. used calibrate_polynomial with a degree of 3 and the measured values, and voila!

ezgif-6-76014465e711