Calculations with sensor values

Dear @thekevinkalis,
I am trying to do the same as you did, SNMP sensors to monitor a WIN machine, in my case the NUC on which my Hass runs in a VM under VirtualBox.
I have tried to use SNMPWalk, but I can’t figure out how to retrieve the OIDs I need: disk total space, disk free space, memory, CPU, etc.
Could you please share the OIDs you used? Or your sensors config.? I am a bit desperate.
Thanks!

I ended up using OID Browser, I found the interface much more user friendly. With a bit of clicking around, you get a feel for the structure and where the OIDs are. I’m assuming you’ve enabled the SNMP service within Windows and know the community string.

When you have the OIDs, you have to create sensors for each value, ie. “Total Disk Space”, “Used Disk Space” etc. You then have to create a separate sensor to calculate the available disk space.

Here’s an example of one of the sensors:

- platform: snmp
  host: 192.168.2.200
  name: adUsed_Disk_C
  community: public
  baseoid: 1.3.6.1.2.1.25.2.3.1.6.1

Personally, I could never get a consistent reading from the CPUs, so I just dropped them altogether.

If you need any more help along the way, let me know, I struggled for ages to get this working on my own system, so I feel your pain.

Thanks, I eventually found an OID browser showing enough information.
FYI, for the CPU, I use the Windows Device Portal API, which provides the info (curl in a command_line sensor). It is not always matching 100% what I see in the Task Manager running on the machine, but it is a good indication.

No problem, I’ll try to keep it succinct. I can only really help with the storage OIDs for now, I’ll have to search for the others when I get home.

Fortunately, OIDs are the same across Windows systems, so they stay the same for the C,D,E drive, etc.

For the C-drive, you’d use:

- platform: snmp
  host: 192.168.2.200
  name: adUsed_Disk_C
  community: public
  baseoid: 1.3.6.1.2.1.25.2.3.1.6.1

and

- platform: snmp
  host: 192.168.2.200
  name: adTotal_Disk_C
  community: public
  baseoid: 1.3.6.1.2.1.25.2.3.1.5.1

The “1” on the end represents the drive, ie. 1 = C, 2 = D, 3 = E, and so on. The preceding number, ie the 6 and 5 represent the object, so 6 = Used Space and 5 = Total Disk Space.

That’s pretty much the construct.

As far as the sensor goes to calculate percentage:

- platform: template
  sensors:
    my_sensor_ad_c_used_percent:
      value_template: "{{ ((states.sensor.adused_disk_c.state|int) / (states.sensor.adtotal_disk_c.state|int) *100)|round(1) }}"

I think that should get you well on your way, I’ll see what I can do about the CPU and RAM OIDs.

Thanks, here is my config, finally (in French, but clear enough, I think), with some calculations to have the value in Gb (as they are stored in allocation units). I have left some calculations details instead of a simplified version with parts resolved, just to keep the logic. Some values could be retrieved (units size, etc.), but are not supposed to change, so I hardcoded some.

- platform: snmp
  name: 'Disque dur utilisé'
  host: 192.168.178.75
  baseoid: 1.3.6.1.2.1.25.2.3.1.6.1
  accept_errors: true
  unit_of_measurement: 'Go'
  value_template: ' {{(((value | int) * 4096) / 1000000000) | round(1) }} '
  
- platform: snmp
  name: 'Mémoire virtuelle utilisée'
  host: 192.168.178.75
  baseoid: 1.3.6.1.2.1.25.2.3.1.6.2
  accept_errors: true
  unit_of_measurement: 'Go'
  value_template: ' {{(((value | int) * 65536) / 1000000000) | round(1) }} '
  
- platform: snmp
  name: 'Mémoire physique utilisée'
  host: 192.168.178.75
  baseoid: 1.3.6.1.2.1.25.2.3.1.6.3
  accept_errors: true
  unit_of_measurement: 'Go'
  value_template: ' {{(((value | int) * 65536) / 1000000000) | round(1) }} '
  
- platform: snmp
  name: "Erreurs d'allocation disque"
  host: 192.168.178.75
  baseoid: 1.3.6.1.2.1.25.2.3.1.7.1
  accept_errors: true
  value_template: ' {{ value | int }} '

- platform: snmp
  name: "Temps depuis demarrage"
  host: 192.168.178.75
  baseoid: 1.3.6.1.2.1.25.1.1.0
  accept_errors: true
  unit_of_measurement: 'timeticks'

- platform: template
  sensors:
    snmp_dernier_demarrage:
      friendly_name: "Dernier démarrage"
      device_class: timestamp
      icon_template: 'mdi:timer'
      entity_id: sensor.temps_depuis_demarrage
      attribute_templates:
        timeticks: "{{ states('sensor.temps_depuis_demarrage') | int }} centièmes de seconde"
      value_template: >
        {% set mytime = (as_timestamp(now()) - ((states('sensor.temps_depuis_demarrage') | int) / 100) | int) %}
        {{ strptime(mytime | timestamp_local, '%Y-%m-%d %H:%M:00') }}
    snmp_memoire_ram:
      friendly_name: "Mémoire utilisée"
      entity_id: sensor.memoire_physique_utilisee, sensor.memoire_virtuelle_utilisee
      unit_of_measurement: '%'
      icon_template: 'mdi:memory'
      value_template: " {{ (((states('sensor.memoire_physique_utilisee') | float) / (((128601 | int) * 65536) / 1000000000))*100)|round }} "
      attribute_templates:
        memoire_virtuelle: "{{ (((states('sensor.memoire_virtuelle_utilisee') | float) / (((165465 | int) * 65536) / 1000000000))*100)|round }} %"
    snmp_disque_utilise:
      friendly_name: "Disque utilisé"
      entity_id: sensor.disque_dur_utilise
      unit_of_measurement: '%'
      value_template: " {{ (((states('sensor.disque_dur_utilise') | float) / (((30972671 | int) * 4096) / 1000000000))*100)|round }} "
      icon_template: 'mdi:harddisk'
      attribute_templates:
        taille_occupée: "{{ states('sensor.disque_dur_utilise') }} Go"

Newbie here just getting to grips with sensors in configuraion.yaml. I really like the way that you’ve used the variables to make this tidier (my first time with variables) so thought I’d give it a go.

I attempted this as shown below:

ram_free_percentage:
   value_template: >- 
      {% set t = states('sensor.media_pc_total_ram') | int %}
      {% set u = states('sensor.media_pc_used_ram') | int %}
      {{ ((t - u) / t) x 100 }}
    unit_of_measurement: '%'

But when I check configuration it indicates an error:

Invalid config for [sensor.template]: invalid template (TemplateSyntaxError: expected token ‘end of print statement’, got ‘x’) for dictionary value @ data[‘sensors’][‘ram_free_percentage’][‘value_template’]. Got ‘{% set t = states(‘sensor.media_pc_total_ram’) | int %} {% set u = states(‘sensor.media_pc_used_ram’) | int %} “{{ ((t - u) / t) x 100 }}”’. (See ?, line ?).

I’ve looked at the example on the template help page and can’t see any obvious issue when looking at the examples. Do you any guidance or ideas on what may be causing the error?

You indicate multiplication with an asterisk * not with the letter x. That’s what the error message is carping about:

expected token ‘end of print statement’, got ‘x’

I am doing my first sensor, and it calculates correct:


- platform: template

    sensors:

      elpris_kwh_total:

        value_template: "{{ (((states('sensor.nordpool_kwh_dk2_dkk_3_10_025') | float + (1.64)) |round(2)) | float) }}"

The problem is that the output is display as text, not as a graph in lovelace!!

What do I need to change to get the graph??

image

entities:
  - entity: sensor.nordpool_kwh_dk2_dkk_3_10_025
  - entity: sensor.elpris_kwh_total
hours_to_show: 72
refresh_interval: 0
title: Elpris
type: history-graph
3 Likes

A verry simple and clean way to make calculations! Thanks! :smiley:

Hi!

Maybe you already fixed the problem - but you need to set a unit to the value to get a graph, ie:

- platform: template
    sensors:
      elpris_kwh_total:
        unit_of_measurement: 'DKK/kWh'
        value_template: "{{ (((states('sensor.nordpool_kwh_dk2_dkk_3_10_025') | float + (1.64)) |round(2)) | float) }}"

Cheers,
Thomas

2 Likes

This is very helpful.

In the example below, does the variable water_volume persist across the sensor or just the value_template?

- platform: template
  sensors:
    circulation_time:
      friendly_name: "Circulation time"
      value_template: >-
        {% set lph = states('sensor.total_circulation_lph') | int(none) %}
        {% if lph %}
          {% set hours = 11526 / lph %}
          {% set minutes = ((hours % 1) * 60) | int %}
          {% set hours = (hours - (hours % 1)) | int %}
          {{ '%02i:%02i'%(hours, minutes) }}
        {% else %}
          none
        {% endif %}
    circulation_hours:
      friendly_name: "Circulation hours"
      value_template: >-
        {% set litres_per_hour = states('sensor.total_circulation_lph') | int(none) %}
        {% set water_volume = 11526 | int %}
        {{ water_volume / litres_per_hour }}

Is there a way to have water_volume be a global variable throughout the HA config?

The scope of a Jinja2 variable is limited to the option where it’s defined. So, no, water_volume isn’t defined outside of value_template.

There are no global Jinja2 variables in Home Assistant.

You can store a value in a Helper (input_number, input_text, etc) or use one of the third party custom_components that implement global variables (by storing them in special entities using the same principle as Helpers).

1 Like

Thank you!

I have looked for a custom component for implementing and using global variables. Can you please offer a suggestion.
Thank you.

Really appreciate all the info above. I am having a weird issue. When I enter the below into the developer tools Template section, it returns values as it should. When I add to my sensors.yaml file and reboot, new sensors are not created. Anything obvious standout to anyone? Each grid_usage sensor is a Utility sensor that collects data from other sensor. I don’t think it matters but figured I would mention.

sensor Electricity Cost Sensor:
  - platform: template
    sensors:
      yearly_electricity_cost:
        friendly_name: "Current Yearly Electricity Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.yearly_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
      monthly_electricity_cost:
        friendly_name: "Current Monthly Electricity Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.monthly_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
      daily_electricity_cost:
        friendly_name: "Current Daily Electriciy Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.daily_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}

That is the legacy template format, newer format is here:

Can still use it though, not sure what your first line sensor Electricity Cost Sensor: is for ?

sensor:
  - platform: template
    sensors:
      yearly_electricity_cost:
        friendly_name: "Current Yearly Electricity Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.yearly_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
      monthly_electricity_cost:
        friendly_name: "Current Monthly Electricity Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.monthly_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
      daily_electricity_cost:
        friendly_name: "Current Daily Electriciy Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.daily_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}

Also, no need to reboot, just reload Templates

1 Like

Maybe my current sensors work still because they were created years ago. There aren’t any errors in any of the logs. Will maybe create a new file (template.yaml) and try adding them in the new format there. Then I suspect I need to start migrating all my other template entities.
The Electricity Costs Sensor was a method that I used to group template sensors. I honestly never knew why it didn’t error. In other areas I just use comments now. Below is a larger sample.

######################################## Sensor for basement humidity ##################################
sensor EcoBee Sensors:
  - platform: template
    sensors:
      basement_humidity:
        friendly_name: "Basement Humidity"
        unit_of_measurement: "%"
        value_template: "{{ state_attr('climate.basement', 'current_humidity') }}"
      workout_server_room_humidity:
        friendly_name: "Workout & Server Room Humidity"
        unit_of_measurement: "%"
        value_template: "{{ state_attr('climate.workout_room', 'current_humidity') }}"
      2nd_floor_guest:
        value_template: >-
          {% if state_attr('climate.2nd_floor_guest', 'hvac_action') == "idle" %} OFF
          {% elif state_attr('climate.2nd_floor_guest', 'hvac_action') == "cooling" %} ON
          {% elif state_attr('climate.2nd_floor_guest', 'hvac_action') == "heating" %} ON
          {% endif %}
######################################## Sensor for Electriciy Costs ##################################
sensor Electricity Cost Sensor:
  - platform: template
    sensors:
      yearly_electricity_cost:
        friendly_name: "Current Yearly Electricity Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.yearly_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
        unit_of_measurement: '$'
      monthly_electricity_cost:
        friendly_name: "Current Monthly Electricity Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.monthly_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
        unit_of_measurement: '$'
      daily_electricity_cost:
        friendly_name: "Current Daily Electriciy Cost"
        value_template: >- 
          {% set grid_usage = states('sensor.daily_net_grid_usage') | int %}
          {{ grid_usage * 0.18 }}
        unit_of_measurement: '$'

sensor Electricity Usage Sensor:
  - platform: template
    sensors:
      net_daily_power:
        friendly_name: Net Daily Power
        unit_of_measurement: kWh
        value_template: "{{ states('sensor.daily_grid_usage')|float - states('sensor.daily_solar_generation')|float }}"

Thanks for the help. Placing the sensors under the new Template structure fixed my issue. Final config:

Template:
  - sensor:
    - name: Yearly Electricity Cost
      state: >- 
        {% set grid_usage = states('sensor.yearly_net_grid_usage') | int %}
        ${{ (grid_usage * 0.18) | round(2) }}
    - name: Monthly Electricity Cost
      state: >- 
        {% set grid_usage = states('sensor.monthly_net_grid_usage') | int %}
        ${{ (grid_usage * 0.18) | round(2) }}
    - name: Daily Electricity Cost
      state: >-
          {% set grid_usage = states('sensor.daily_net_grid_usage') | int %}
          ${{ (grid_usage * 0.18) | round(2) }}