Calculating Vapor Pressure Deficit (or VPD) in kPa

I do a bit of indoor growing of various plants and needed a way to calculate the VPD in my environment. These calculations are assuming that the leaf temperature is the same as the environment. You could add some math into the “set T” line to adjust the leaf temp and environment if you wanted.

I searched high and low for code that had already been done but could not find any so I had to figure it out on my own. Below is the code for I use. I hope it helps others.

This sensor calculates in Celsius and assumes you’re measuring your Temperature in Fahrenheit. You’ll have to remove the math that converts to F to C if your setup is measuring in Celsius.

sensor:
  - platform: template
    sensors:
      vapor_deficit:
        friendly_name: 'vpd in kilo pascals'
        value_template: >-
          {% set T = ((states('sensor.th16_si7021_temperature') | float) - 32) * 5/9 %}
          {% set RH = states('sensor.th16_si7021_humidity')|float %}
          {% set SVP = 0.61078 * e ** (17.2694 * T / (T + 238.3)) %}
          {% set VPD = ((100-RH) / 100) * SVP %}
          {{-VPD | round(2) -}}
        unit_of_measurement: 'kPa'
7 Likes

Thanks for sharing!

Just an FYI, the Sharing your Projects! category is generally used for something like this. This (Configuration) category is generally for asking for help.

Moved.

I didn’t see that. I can move it .

Already done :slight_smile:

Shoot. I already made a new topic there. Can you delete that one?

Looks like you already deleted it?

Hi there!
Thank you for sharing this… I’m trying to use the code, but for some reason I can’t make it calculate the VPD. It only shows 0.61 kpa. What I’m missing here?

sensor:
 - platform: template
   sensors:
    vapor_deficit:
     friendly_name: "vpd em kPa"
     value_template: >-
       {% set T = states('sensor.sonoff_10000xxxx_temperature')|float %}
       {% set RH = states('sensor.sonoff_10000xxxx_humidity')|float %}
       {% set SVP = 0.61078 * e ** (17.2694 * T / (T + 238.3)) %}
       {% set VPD = ((100-RH) / 100) * SVP %}
       {{-VPD | round(2) -}}
     unit_of_measurement: 'kPa'

Just solved the problem after reading alexxIT/sonoffLAN. You must create a new template for temperature and humidity sensor:

sensor:
 - platform: template
   sensors:
     temperature_purifier:
      friendly_name: Temperature
      device_class: temperature
      value_template: "{{ state_attr('switch.sonoff_1000xxxx', 'temperature') }}"
     humidity_purifier:
      friendly_name: Humidity
      device_class: humidity
      value_template: "{{ state_attr('switch.sonoff_1000xxxx', 'humidity') }}"

No, you did not have to do that. You just had to adjust the original template to use your device attributes. However there is no way we could have known your originally specified sensors were incorrect. Only you have access to your developer tools / states menu and thus only you could have known that. Here is what it would look like:

sensor:
 - platform: template
   sensors:
    vapor_deficit:
     friendly_name: "vpd em kPa"
     value_template: >-
       {% set T = state_attr('switch.sonoff_1000xxxx', 'temperature')|float %}
       {% set RH = state_attr('switch.sonoff_1000xxxx', 'humidity')|float %}
       {% set SVP = 0.61078 * e ** (17.2694 * T / (T + 238.3)) %}
       {% set VPD = ((100-RH) / 100) * SVP %}
       {{-VPD | round(2) -}}
     unit_of_measurement: 'kPa'

There is an argument for breaking the temperature and humidity attributes out of the switch entity like you did if you want easier access to them for display in Lovelace and as automation triggers, but it was not required for this sensor.

2 Likes

Hi, thank you for clarifying this!
I’m pretty sure I’ve tried that way you say and didn’t work. Anyway, it’s working now, but I will try again to implement without breaking out the humidity and temp attributes from the switch entity. I’m just out of time now…

You sir are a legend! I was travelling your same path, then google led me here. Up and running in 2 minutes. Thanks !

1 Like

I’m glad it could help you.

I like the air VPD and the saturated leaf as seperate numbers.
In my example I have a helper slider (input_number.flower_leaf_temp_offse) so I can set my leaf temp and calculate the different VPDs

      flower_vpd:
        friendly_name: "Flower VPD"
        value_template: >-
          {% set FT = states('sensor.flower_tent_temp')|float %}
          {% set FLTO = states('input_number.flower_leaf_temp_offset')|float %}
          {% set FRH = states('sensor.flower_tent_humidity')|float %}
          {% set FLT = FT + FLTO %}
          {% set SVPF = 0.61078 * e ** (17.2694 * FLT / (FLT + 238.3)) %}
          {% set VPDF = ((100-FRH) / 100) * SVPF %}
          {{-VPDF | round(2) -}}
        unit_of_measurement: "kPa"

      flower_air_vpd:
        friendly_name: "Flower Air VPD"
        value_template: >-
          {% set FAT = states('sensor.flower_tent_temp')|float %}
          {% set FARH = states('sensor.flower_tent_humidity')|float %}
          {% set ASVPF = 0.61078 * e ** (17.2694 * FAT / (FAT + 238.3)) %}
          {% set AVPDF = ((100-FARH) / 100) * ASVPF %}
          {{-AVPDF | round(2) -}}
        unit_of_measurement: "kPa"
5 Likes

This is awesome! Thank you!

As far as calculating leaf vpd don’t I just subtract the difference between the air and leaf on line that calculates for T as suggested above? My average leaf surface is about 2 degrees less than the air. So I’m using:

{% set T = (((states(‘sensor.flower1_temp’) | float) - 32) * 5/9 - 2) %}

`

When I wrote this up I was under the impression that leaf temp was a bigger deal than it really was for the plants I grow. I no longer worry about calculating leaf temp and instead use a 2nd temperature sensor and average that into the VPD equation.

Here is my code that uses a slider for Leaf Temperature Offset, calculates vpsat (leaf VP) and vpair (air VP) and finds the difference b/w the two.

  - platform: template
    sensors:
      vpsat:
        friendly_name: "Leaf Vapor Pressure"
        value_template: >-
          {% set FT = states('sensor.tempavg')|float %}
          {% set FLTO = states('input_number.flower_leaf_temp_offset')|float %}
          {% set FLT = FT - FLTO %}
          {% set VPDF = (610.7 * 10 ** ((7.5*FLT)/(237.3+FLT)) / 1000) %}
          {{-VPDF | round(2) -}}
        unit_of_measurement: "kPa"

      vpair:
        friendly_name: "Air Vapor Pressure"
        value_template: >-
          {% set FAT = states('sensor.tempavg')|float %}
          {% set FARH = states('sensor.humidityavg')|float %}
          {% set ASVPF = (610.7 * 10 ** ((7.5*FAT)/(237.3+FAT)) / 1000) %}
          {% set AVPDF = ((FARH) / 100) * ASVPF) %}
          {{-AVPDF | round(2) -}}
        unit_of_measurement: "kPa"
      
      vpdcalc:
        friendly_name: "VPD"
          unit_of_measurement: 'kPa'
          value_template: "{{ float(states('sensor.vpsat')) - float(states('sensor.vpair')) }}"
1 Like

If someone is still looking for a working template to calculate the absolute humidity very accurately, here is my template that I created based on this calculation: Berechnung von Taupunkt und relativer Feuchte. Since the temperature inside the house should not fall below zero degrees, the calculation only works for positive values. For outside, there would still need to be a query, details can be found on the website mentioned.
The OpenWeatherMap integration is required to get the air pressure. The temperature must be in degrees Celsius, otherwise first convert from Kelvin to Celsius. The result is rounded to two digits and corresponds exactly to the results of the online calculators.

- platform: template
  sensors:
    scd30_abs_luftfeuchtigkeit:
      value_template: >-
        {% set r = states('sensor.scd30_rel_luftfeuchtigkeit') | float(default=0) %}
        {% set t = states('sensor.scd30_temperatur') | float(default=0) %}
        {% set p = states('sensor.openweathermap_pressure') | float(default=0) %}
        {% set sdd =  6.1078 * 10**((7.5 * t)/(237.3 + t)) | float(default=0) %}
        {% set dd =  r/100 * sdd | float(default=0) %}
        {% set af = 10**5 * 18.016/8314.3 * dd/ (t + 273.15) | float(default=0) %}
        {{round(af , 2)}}
      unit_of_measurement: "%"

Edit: It is working by using the min/max/mean then using that in the code below.

Can anyone help me here? I am trying to get an average VPD from 5 different sensors in the room. My code currently showing as unavailable.

sensor:
  - platform: template
    sensors:
      vapor_deficit:
        friendly_name: 'Flower 2 VPD Sensor'
        unique_id: CqM2zf9c
        value_template: >-
          {% set T = ((states(('sensor.flower_2_sensor_1_temp'+'sensor.flower_2_sensor_2_temp'+'sensor.flower_2_sensor_3_temp'+'sensor.flower_2_sensor_4_temp'+'sensor.flower_2_sensor_5_temp')/5) | float) - 32) * 5/9 %}
          {% set RH = states(('sensor.flower_2_sensor_1_rh'+'sensor.flower_2_sensor_2_rh'+'sensor.flower_2_sensor_3_rh'+'sensor.flower_2_sensor_4_rh'+'sensor.flower_2_sensor_5_rh')/5)|float %}
          {% set SVP = 0.61078 * e ** (17.2694 * T / (T + 238.3)) %}
          {% set VPD = ((100-RH) / 100) * SVP %}
          {{-VPD | round(2) -}}
        unit_of_measurement: 'kPa'

Have you tried creating two separate value templates for the average temps and humidity and then plugging those templates into the VDP template?