Water Cost Sliding Scale

In South Africa our water is billed on a sliding scale based on consumption.
0 - 10kl - $1 per kl
10kl - 20kl $2 per kl (plus the $1 per kl fr the first 10kl)
20kl - 30kl 4# per kl (plus the $110kl and 210kl)

And so on. I’m pretty sure there’s no mechanism in HA to support this calculation natively. What’s my best option to caclulate water costs? I figure I could write a script, using helper variables to contain the cost for each usage bucket, but not sure how to elegantly call the script and write a value back that can be used by the built in dashboards.

https://www.home-assistant.io/integrations/utility_meter/ is built to help with this.

Pass your total water consumption sensor into a utility meter, configured with 3 tariffs, you can call them rate_1, rate_2, rate_3.

This will give you 3 water sensors, one per rate. Add each of these to the energy board, with a fixed price of $1, $2, $4 respectively.

The utility meter creates a select entity that picks the active rate. At the start of the billing cycle, set the select back to rate_1. When the rate_1 sensor exceeds 10kL, automate the select to switch to rate_2. When the rate_2 sensor exceeds 10kL, switch the select to rate_3.

I did something similar to calculate my waste costs usin a template sensor:

template:
  sensor:
    - name: Tibi résiduel ytd
      unique_id: tibi_residuel_ytd
      state_class: total
      device_class: weight
      unit_of_measurement: kg
      state: >
        {% set value_json = tibi_history['stdout'] | from_json %}
        {% set rest_history = value_json.history[0].card.products | selectattr('status', "eq", 'active') | selectattr('fraction', "eq", 'REST') | map(attribute='emptyings') | list %}
        {% set ns = namespace(weight=0) -%}

        {% if rest_history[0] | count > 0 %}
          {% for k in rest_history[0] %}
            {% set ns.weight = ns.weight +  rest_history[0][k]["weight"]| float %}
          {% endfor %}
          {{ ns.weight }}
        {% else %}
          unavailable
        {% endif %}
      attributes:
        vidanges: >
          {% set value_json = tibi_history['stdout'] | from_json %}
          {% set rest_history = value_json.history[0].card.products | selectattr('status', "eq", 'active') | selectattr('fraction', "eq", 'REST') | map(attribute='emptyings') | list %}
          {{ rest_history[0] | count }}
  - name: Tibi résiduel ytd prix
    unique_id: tibi_residuel_ytd_price
    state_class: total
    device_class: monetary
    unit_of_measurement: "€"
    availability: '{{ is_number(states("sensor.tibi_residuel_ytd"))}}'
    state: >
      {% set ns = namespace(price=0,people=2,includedw=0,includedv=0) -%}
      {% set wt = states("sensor.tibi_residuel_ytd") | float %}
      {% set w1 = [wt,ns.people*90.0] | min %}
      {% set ns.price = ns.price + 0.25 * w1|float %}
      {% set wt = wt - w1 %}
      {% if wt > 0 %}
        {% set w2 = [wt,ns.people*20.0] | min %}
        {% set ns.price = ns.price + 0.40 * w2|float %}
        {% set wt = wt - w2 %}
      {% endif %}
      {% if wt > 0 %}
        {% set ns.price = ns.price + 0.60 * wt|float %}
      {% endif %}
      {{ [0,ns.price - (ns.includedw * ns.people * 0.25) + ((state_attr("sensor.tibi_residuel_ytd", "vidanges") | float - ns.includedv) * 0.60)] | max }}