[GUIDE] Australian Electricity Demand tariffs (e.g AGL)

OK so you have an integration for your inverter, that creates its own sensors called.

sensor.electricity_imported_power_kwh
sensor.electricity_exported_power_kwh

Just checking through and you have defined ''sensor.electricity_imported_power_kwh" as a source in the utility meter, in these two sections.

utility_meter:
  electricity_imported_power_daily:
    source: sensor.electricity_imported_power_kwh  #Comment: Replace this sensor with your own sensor that provides kWh your importing from the grid
    name: Electricity Imported Power Daily
    cycle: daily
    tariffs:
      - peak
      - shoulder
      - off-peak

and

  electricity_imported_demand:
    source: sensor.electricity_imported_power_kwh  #Comment: Replace this sensor with your own sensor that provides kWh your importing from the grid
    name: Electricity Imported Demand
    cron: 0,30 * * * *
    tariffs:
      - high-demand
      - low-demand
      - no-demand

but I note that there’s nowhere that you have ‘sensor.electricity_exported_power_kwh’ used as a source. Should this be defined, or is it missing (from above code windows) ?

Whilst the code windows in the OP are great, working through explaining what they are doing. It would probably be easiest, when posting to the community, to then have a code window that contains the entire code for each file in your add-on.
The within that window, next to your code that everyone should change the data source, to specify their own local version of this source, just add “#Comment - Replace this with …”.

Whilst using the /config/packages directory and placing your code there, but then adding the automation ‘via the web GUI’ (that then stores that code in /config/automations.yaml file), you could wrap this into a /config/packages/energy_costs.yaml file with:

binary_sensor:
  - platform: workday
    name: Weekday Sensor
    country: AU
    province: NSW

sensor:
  - platform: time_date
    display_options:
      - "date"

utility_meter:
  electricity_imported_power_daily:
    source: sensor.electricity_imported_power_kwh  #Comment: Replace this sensor with your own sensor that provides kWh your importing from the grid
    name: Electricity Imported Power Daily
    cycle: daily
    tariffs:
      - peak
      - shoulder
      - off-peak

  electricity_demand_max_monthly:
    source: sensor.electricity_demand_max
    name: Electricity Demand Max Monthly
    cycle: yearly
    tariffs:
      - 1
      - 2
      - 3
      - 4
      - 5
      - 6
      - 7
      - 8
      - 9
      - 10
      - 11
      - 12

  electricity_imported_demand:
    source: sensor.electricity_imported_power_kwh  #Comment: Replace this sensor with your own sensor that provides kWh your importing from the grid
    name: Electricity Imported Demand
    cron: 0,30 * * * *
    tariffs:
      - high-demand
      - low-demand
      - no-demand

template:
  - sensor:
      - name: "Electricity Demand Max"
        unique_id: electricity_demand_max_sensor
        unit_of_measurement: kWh
        state: >
          {{ states('input_number.electricity_demand_max') |float(0) }}

      - name: Days Remaining in Month
        unique_id: days_remaining_in_month
        state: >
          {% set this = now().replace(hour=0).replace(minute=0).replace(second=0).replace(microsecond=0) %}
          {% set next = this.month + 1 if this.month + 1 <= 12 else 1 %}
          {% set last = this.replace(month=next, day=1) %}
          {{ (last.date() - this.date()).days - 1 }}

      - name: Total Daily Import Cost
        icon: mdi:currency-usd
        state_class: total_increasing
        device_class: monetary
        unit_of_measurement: $
        state: >
          {% set supply = states('sensor.electricity_supply_charge') | float(0) %}
          {% set offpeak = states('sensor.electricity_imported_power_daily_off_peak') | float(0) * states('sensor.electricity_import_rate_off_peak') | float(0) %}
          {% set shoulder = states('sensor.electricity_imported_power_daily_shoulder') | float(0) * states('sensor.electricity_import_rate_shoulder') | float(0) %}
          {% set peak = states('sensor.electricity_imported_power_daily_peak') | float(0) * states('sensor.electricity_import_rate_peak') | float(0) %}
          {{ (supply + offpeak + shoulder + peak) | round(2) }}

      - name: "Electricity Total Cost Daily"
        unique_id: electricity_total_cost_daily
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.electricity_supply_charge') | float(0) %}
          {% set offpeak = states('sensor.electricity_imported_power_daily_off_peak') | float(0) * states('sensor.electricity_import_rate_off_peak') | float(0) %}
          {% set shoulder = states('sensor.electricity_imported_power_daily_shoulder') | float(0) * states('sensor.electricity_import_rate_shoulder') | float(0) %}
          {% set peak = states('sensor.electricity_imported_power_daily_peak') | float(0) * states('sensor.electricity_import_rate_peak') | float(0) %}
          {% set feedintariff = states('sensor.electricity_exported_power_daily') | float(0) * states('sensor.electricity_export_rate') | float(0) %}
          {% set t = now() %}
          {% if t.month in [4,5,9,10] %}
            {% set demandrate = states('sensor.electricity_import_rate_low_demand') | float(0) %}
          {% else %}
            {% set demandrate = states('sensor.electricity_import_rate_high_demand') | float(0) %}
          {% endif %}
          {% set demand = states('input_number.electricity_demand_max') | float (0) * 2 * demandrate %}
          {{ (supply + offpeak + shoulder + peak - feedintariff) | round(2) }}


      - name: "Electricity Demand Monthly Cost"
        unique_id: electricity_demand_monthly_cost
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set t = now() %}
          {% if t.month in [4,5,9,10] %}
            {% set demandrate = states('sensor.electricity_import_rate_low_demand') | float(0) %}
          {% else %}
            {% set demandrate = states('sensor.electricity_import_rate_high_demand') | float(0) %}
          {% endif %}
          {{states('input_number.electricity_demand_max') | float (0) * 2 * demandrate * ( now().day + states('sensor.days_remaining_in_month') | int(0) ) }}


      - name: "Electricity Total Cost Yearly"
        unique_id: electricity_total_cost_yearly
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.electricity_supply_charge') | float(0) * ( states('sensor.days_passed_in_year') | int(0) + 1 ) %}
          {% set offpeak = states('sensor.electricity_imported_power_yearly_off_peak') | float(0) * states('sensor.electricity_import_rate_off_peak') | float(0) %}
          {% set shoulder = states('sensor.electricity_imported_power_yearly_shoulder') | float(0) * states('sensor.electricity_import_rate_shoulder') | float(0) %}
          {% set peak = states('sensor.electricity_imported_power_yearly_peak') | float(0) * states('sensor.electricity_import_rate_peak') | float(0) %}
          {% set feedintariff = states('sensor.electricity_exported_power_yearly') | float(0) * states('sensor.electricity_export_rate') | float(0) %}
          {% set highdemandrate = states('sensor.electricity_import_rate_high_demand') | float(0) %}
          {% set lowdemandrate = states('sensor.electricity_import_rate_low_demand') | float(0) %}
          {% set demand = ( states('sensor.electricity_demand_max_monthly_1')| float (0) * 31 + states('sensor.electricity_demand_max_monthly_2') | float (0) * 28 + states('sensor.electricity_demand_max_monthly_3') | float (0) * 31 + states('sensor.electricity_demand_max_monthly_6') | float (0) * 30 + states('sensor.electricity_demand_max_monthly_7') | float (0) * 31 + states('sensor.electricity_demand_max_monthly_8') | float (0) * 31 + states('sensor.electricity_demand_max_monthly_11') | float (0) * 30 + states('sensor.electricity_demand_max_monthly_12') | float (0) * 31 ) * 2 * highdemandrate + ( states('sensor.electricity_demand_max_monthly_4') | float (0) * 30 + states('sensor.electricity_demand_max_monthly_5') | float (0) * 31 + states('sensor.electricity_demand_max_monthly_9') | float (0) * 30 + states('sensor.electricity_demand_max_monthly_10') | float (0) * 31 ) * 2 * lowdemandrate %} 
          {{ (supply + offpeak + shoulder + peak + demand - feedintariff) | round(2) }}


      - name: Electricity Import Rate High Demand
        unique_id: electricity_import_rate_high_demand
        icon: mdi:cash-minus
        unit_of_measurement: $/kWh
        state: 0.15400

      - name: Electricity Import Rate Low Demand
        unique_id: electricity_import_rate_low_demand
        icon: mdi:cash-minus
        unit_of_measurement: $/kWh
        state: 0.15400

      - name: Electricity Import Rate Peak
        unique_id: electricity_import_rate_peak
        icon: mdi:cash-minus
        unit_of_measurement: $/kWh
        state: 0.23100

      - name: Electricity Import Rate Shoulder
        unique_id: electricity_import_rate_shoulder
        icon: mdi:cash-minus
        unit_of_measurement: $/kWh
        state: 0.18700

      - name: Electricity Import Rate Off Peak
        unique_id: electricity_import_rate_off_peak
        icon: mdi:cash-minus
        unit_of_measurement: $/kWh
        state: 0.13200

      - name: Electricity Export Rate
        unique_id: electricity_export_rate
        icon: mdi:cash-plus
        unit_of_measurement: $/kWh
        state: 0.06000

      - name: Electricity Supply Charge
        unique_id: electricity_supply_charge
        icon: mdi:cash-plus
        unit_of_measurement: $/day
        state: 1.4300

input_number:
  electricity_demand_max:
    name: Electricity Demand Max Value
    # initial: 0 # don't use initial as it will reset upon restart
    min: 0
    max: 20
    step: 0.001

and the /config/automations.yaml file, with:

alias: Set Electricity Tariff
description: 'Set the daily peak, shoulder and off-peak periods'
trigger:
  - platform: time
    at: '07:00:00'
  - platform: time
    at: '17:00:00'
  - platform: time
    at: '20:00:00'
  - platform: time
    at: '22:00:00'
  - platform: homeassistant
    event: start
condition: []
action:
  - service: select.select_option
    data:
      option: >-
        {% set t = now() %}  {%- if t.hour >=17 and t.hour <20 and
        is_state('binary_sensor.workday_sensor', 'on') %}
          peak
        {%- elif t.hour >= 22 or t.hour < 7 -%}
          off-peak
        {%- else -%}
          shoulder
        {%- endif -%}
    target:
      entity_id:
        - select.electricity_solar_panel_production_daily
        - select.electricity_house_consumption_daily
        - select.electricity_imported_power_daily
        - select.electricity_solar_panel_production_monthly
        - select.electricity_house_consumption_monthly
        - select.electricity_imported_power_monthly
        - select.electricity_solar_panel_production_yearly
        - select.electricity_house_consumption_yearly
        - select.electricity_imported_power_yearly
mode: single

# ----------------------------------------------------------

alias: Set Electricity Demand Tariff
description: 'Set the Peak or Off Peak DEMAND months of the year'
trigger:
  - platform: time
    at: '14:00:00'
  - platform: time
    at: '17:00:00'
  - platform: time
    at: '20:00:00'
  - platform: time
    at: '21:00:00'
  - platform: homeassistant
    event: start
condition: []
action:
  - service: select.select_option
    data:
      option: >-
        {% set t = now() %}   {% if is_state('binary_sensor.workday_sensor',
        'on') %}
          {%- if ( t.hour >=17 and t.hour <20 and t.month in [11,12,1,2,3] ) or ( t.hour >=17 and t.hour <20 and t.month in [6,7,8] ) -%}
            high-demand
          {%- elif t.hour >= 17 and t.hour < 20 and t.month in [4,5,9,10] -%}
            low-demand
          {%- else -%}
            no-demand
          {%- endif -%}
        {%- else -%}
          no-demand
        {%- endif -%}
    target:
      entity_id:
        - select.electricity_imported_demand
    enabled: true
mode: single

# ----------------------------------------------------------

alias: Store max demand usage
description: Calculate and store max 30 minute demand in input_value to survive a reboot
trigger:
  - platform: state
    entity_id:
      - sensor.electricity_imported_demand_high_demand
      - sensor.electricity_imported_demand_low_demand
condition:
  - condition: template
    value_template: >-
      {{ (trigger.to_state.state | float(0)) >
      (states('input_number.electricity_demand_max') | float()) }}
action:
  - service: input_number.set_value
    data:
      value: '{{ trigger.to_state.state | float() | round(3) }}'
    target:
      entity_id:
        - input_number.electricity_demand_max
mode: single

# ----------------------------------------------------------

alias: Set Monthly max demand and reset Stored Max Value
description: ''
trigger:
  - platform: time
    at: '00:00:00'
  - platform: homeassistant
    event: start
condition:
  - condition: template
    value_template: '{{ now().day == 1 }}'
action:
  - service: select.select_option
    data:
      option: '{{ now().month }}'
    target:
      entity_id:
        - select.electricity_demand_max_monthly
  - service: input_number.set_value
    data:
      value: 0
    target:
      entity_id:
        - input_number.electricity_demand_max
mode: single

# ----------------------------------------------------------
Note: The billing periods / costs above are slightly modified from the original code, to fit into the Demand plan Essential Energy offers us, that is one demand type charge all year round and peak is only 5-8pm weekdays / shoulder 7am-5pm and 8-10pm.

This guide intended to focus on the demand config so yes I had neglected to mention the export value initially.

You will need a utility meter with a daily cycle for the daily cost calculation. A monthly cycle for the monthly calculation etc. No tariffs as you probably have a flat export rate.

Edit: I have added to the OP and also included a complete energy_cost.yaml example at the end of the OP.

I discovered today that in NSW it is a bank holiday however this is not a public holiday, therefore the workday sensor was incorrectly ignoring demand usage this evening. I have corrected this in the OP using a remove_holidays property.

For anyone else curious, here is a link to the current holidays repo on github: Python Holidays

Sorry just getting back to revisting this, and getting it going.

Great stuff ! Have started afresh and going from this /config/packages/energy_cost.yaml, and editing for NSW with additional 7am-9am peak hours and (currently) no demand fee (easiest to just use cost for these is $0.00, allowing their activation in future by just updating the price).

I note that you mention you also have an energy.yaml file, any chance you can post that, to allow modification and re-use?

Any chance you’ve already developed a tarrif tracker for gas and water in Oz ? :grinning:

Yep, good thinking. it’ll work for either.

I’m not going to post it but instead link you to where i sourced it from which I think is better, as it’s been updated and improved since i did mine. Solaredge Modbus Configuration for Single Inverter and Battery - Share your Projects! - Home Assistant Community (home-assistant.io)
My cost sensors and everything started with the work from the previous version of that post, i then split out my cost file as making it work with demand tariffs added a fair few lines and I just liked organising costs into it’s own package.

Yes, kinda.

Water is easy, although i have not figured out my personal daily supply charge yet so it’s only showing me usage on my dashboard for now. the cost is there tough.

template:
  - sensor:
      - name: Water Consumption
        unique_id: water_consumption
        state: "{{ states('counter.water_counter') | float(0) * 0.5 }}"
        unit_of_measurement: "L"
        icon: mdi:water-pump
        device_class: water
        state_class: total_increasing

      - name: Water Import Rate
        unique_id: water_import_rate
        icon: mdi:cash-minus
        unit_of_measurement: "AUD/L"
        state: "0.00239"
      - name: Water Supply Charge
        unique_id: water_supply_charge
        icon: mdi:cash-minus
        unit_of_measurement: "AUD/L"
        state: "0"

      - name: "Water Total Cost Daily"
        unique_id: water_total_cost_daily
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.water_supply_charge') | float(0) %}
          {% set usage = states('sensor.water_consumption_daily') | float(0) * states('sensor.water_import_rate') | float(0) %}
          {{ (supply + usage) | round(2) }}
      - name: "Water Total Cost Monthly"
        unique_id: water_total_cost_monthly
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.water_supply_charge') | float(0) * now().day %}
          {% set usage = states('sensor.water_consumption_monthly') | float(0) * states('sensor.water_import_rate') | float(0) %}
          {{ (supply + usage) | round(2) }}
      - name: "Water Total Cost Yearly"
        unique_id: water_total_cost_yearly
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.water_supply_charge') | float(0) * ( states('sensor.days_passed_in_year') | int(0) + 1 ) %}
          {% set usage = states('sensor.water_consumption_yearly') | float(0) * states('sensor.water_import_rate') | float(0) %}
          {{ (supply + usage) | round(2) }}

utility_meter:
  water_consumption_daily:
    source: sensor.water_consumption
    name: Water Consumption Daily
    cycle: daily
  water_consumption_monthly:
    source: sensor.water_consumption
    name: Water Consumption Monthly
    cycle: monthly
  water_consumption_yearly:
    source: sensor.water_consumption
    name: Water Consumption Yearly
    cycle: yearly

Currently my gas.yaml is identical to that. Gas for me is billed at 3 rates, first xxxxMJ, next yyyyMJ and the rest zzzzMJ, but the bill doesnt make sense because my total usage last bill was less than xxxx yet i was charged some gas at all three rates. Once i work that out i’ll implement the tiers. For now i just use the same as above with one extra conversion for converting between m3 and MJ.

template:
  - sensor:
      - name: Gas Consumption M3
        unique_id: gas_consumption_m3
        state: "{{ states('counter.gas_counter') | float(0) * 0.01 }}"
        unit_of_measurement: "m³"
        icon: mdi:fire
        device_class: gas
        state_class: total_increasing
      - name: Gas Consumption MJ
        unique_id: gas_consumption_mj
        state: "{{ states('sensor.gas_consumption_m3') | float(0) * 37 }}"
        unit_of_measurement: "MJ"
        icon: mdi:fire
        device_class: gas
        state_class: total_increasing

      - name: Gas Import Rate MJ
        unique_id: gas_import_rate_mj
        icon: mdi:cash-minus
        unit_of_measurement: "AUD/MJ"
        state: "0.031218"
      - name: Gas Import Rate M3
        unique_id: gas_import_rate_m3
        icon: mdi:cash-minus
        unit_of_measurement: "AUD/m³"
        state: "{{ states('sensor.gas_import_rate_mj') | float(0) * 37 }}"
      - name: Gas Supply Charge
        unique_id: gas_supply_charge
        icon: mdi:cash-minus
        unit_of_measurement: "AUD"
        state: "0.65142"

      - name: "Gas Total Cost Daily"
        unique_id: gas_total_cost_daily
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.gas_supply_charge') | float(0) %}
          {% set usage = states('sensor.gas_consumption_daily') | float(0) * states('sensor.gas_import_rate_m3') | float(0) %}
          {{ (supply + usage) | round(2) }}
      - name: "Gas Total Cost Monthly"
        unique_id: gas_total_cost_monthly
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.gas_supply_charge') | float(0) * now().day %}
          {% set usage = states('sensor.gas_consumption_monthly') | float(0) * states('sensor.gas_import_rate_m3') | float(0) %}
          {{ (supply + usage) | round(2) }}
      - name: "Gas Total Cost Yearly"
        unique_id: gas_total_cost_yearly
        icon: mdi:currency-usd
        unit_of_measurement: $
        state_class: total
        device_class: monetary
        state: >
          {% set supply = states('sensor.gas_supply_charge') | float(0) * ( states('sensor.days_passed_in_year') | int(0) + 1 ) %}
          {% set usage = states('sensor.gas_consumption_yearly') | float(0) * states('sensor.gas_import_rate_m3') | float(0) %}
          {{ (supply + usage) | round(2) }}

utility_meter:
  gas_consumption_daily:
    source: sensor.gas_consumption_m3
    name: Gas Consumption Daily
    cycle: daily
  gas_consumption_monthly:
    source: sensor.gas_consumption_m3
    name: Gas Consumption Monthly
    cycle: monthly
  gas_consumption_yearly:
    source: sensor.gas_consumption_m3
    name: Gas Consumption Yearly
    cycle: yearly

My council just charges an annual fee based upon the size (diameter) of the connection. For me this is 20mm connection for $177 per annum, that they then just charge 25% of per quarterly bill. Assuming your probably the same with your council.

Would it be simplest to work on using an extrapolated daily rate for the water_supply_charge ?
i.e. $177 / 4 = $44.25. Then $44.25 / 90 = $0.4916666666666667 per day (i.e. 360 days p.a. , this works out more accurate than $177 / 365).

Even though HA Energy doesn’t allow for a “sewerage meter” LoL, if we want to show the water bill more accurately aligning to the quarterly bill, we can factor in the daily sewerage cost ?
Instead of adding a sensor for sewerage_supply_charge and then having to update the formulas to add this into the total, this could be simply added by adding this into the water_supply_charge daily rate.

For example my council is $790 p.a. for sewerage, divide this by 365 = $2.164383561643836 per day.
Adding $2.164383561643836 (sewer) and $0.4916666666666667 (water) supply charges gives an extrapolated daily fees of $2.656050228310503 that will provide a supply charge within a few $ each quarter. ?


Looking at the gas and referencing a bill:

Gas

It looks like whilst the gas meter gets a pulse for every 10L (or 0.01m3) they then multiply this by a “correction factor” to account for the changes in volume causes by temperature, before it is then multipled by the “heating value” (that seems to vary according to the supplier you have… 38.3 seems to be the scientific rate though) to convert it to MJ.

To add in the correction factor, thinking would an addition sensor be required, instead of adding the correction to gas_consumption_m3? Having gas_consumption_m3 and then another sensor for gas_consumption_corrected_m3 would then mean you have a sensor tracking the actual gas meter reading to match up to the paper bill, whilst then having another sensor that has the corrected m3 that can then be used in calculating the HA daily/weekly gas bill?

This would mean your code could be updated with:

      - name: Gas Consumption M3
        unique_id: gas_consumption_m3
        state: "{{ states('counter.gas_counter') | float(0) * 0.01 }}"
        unit_of_measurement: "m³"
        icon: mdi:fire
        device_class: gas
        state_class: total_increasing

      - name: Gas Consumption M3 (Corrected)
        unique_id: gas_consumption_m3_corrected
        state: "{{ states('sensor.gas_consumption_m3') | float(0) * 0.9775 }}"   # Change 0.9775 to your retailers CORRECTION FACTOR
        unit_of_measurement: "m³"
        icon: mdi:fire
        device_class: gas
        state_class: total_increasing

      - name: Gas Consumption MJ
        unique_id: gas_consumption_mj
        state: "{{ states('sensor.gas_consumption_m3_corrected') | float(0) * 38.3 }}"
        unit_of_measurement: "MJ"
        icon: mdi:fire
        device_class: gas
        state_class: total_increasing

I assume this would also then mean adding to the utility_meter(s) to have:

utility_meter:
  gas_consumption_daily:
    source: sensor.gas_consumption_m3
    name: Gas Consumption Daily
    cycle: daily
  gas_consumption_daily_corrected:
    source: sensor.gas_consumption_m3_corrected
    name: Gas Consumption Daily (Corrected)
    cycle: daily
  gas_consumption_monthly:
    source: sensor.gas_consumption_m3
    name: Gas Consumption Monthly
    cycle: monthly
  gas_consumption_monthly_corrected:
    source: sensor.gas_consumption_m3_corrected
    name: Gas Consumption Monthly (Corrected)
    cycle: monthly
  gas_consumption_yearly:
    source: sensor.gas_consumption_m3
    name: Gas Consumption Yearly
    cycle: yearly
  gas_consumption_yearly_corrected:
    source: sensor.gas_consumption_m3_corrected
    name: Gas Consumption Yearly (Corrected)
    cycle: yearly

Not sure if this is correct, trying to follow the code, it appears that you convert the m3 into MJ (since thats what retailers bill upon) in gas_consumption_mj then you define the baseline (i.e. 0-1905mj rate) in gas_import_rate_mj next I’d assume is to multiple the mj consumed by the cost per mj. This appears to be the intent in what you’ve called gas_import_rate_m3 ?

        state: "{{ states('sensor.gas_import_rate_mj') | float(0) * 37 }}"

But looking at the state/formula it appears to be saying to take the gas_consumption_mj by the retailers heating value, and not by the number of mj you’ve consume? If this is supposed to be per mj $ x mj consumed, shouldn’t it be:

        state: "{{ states('sensor.gas_import_rate_mj') | float(0) * gas_consumption_mj }}"

All this might be OK for the rolling daily amount, but as you mention there’s the mj usage tiers they charge at, and this appears to not be based upon the usage per day, but instead the usage for the 90-92 billing period. With the total mj used over that period, then being broken down into tier 1 (0-1905mj with Origin), tier 2 (1905-252,558mj with Origin) and then “Remaining” (i.e. 252,558mj+).

NFI for the code to do this, but I would assume this means whilst the daily mj/$ bill showing might be OK for tracking purposes. To get near accurate for the monthly, it means adding up x months prior mj consumed and then trying to break it down into 0-1905 and 1905-252558 etc tiers and their associated cost, then total them up.

Still that isn’t going to be very accurate, as your then just taking the last x months mj, as the basis for these calculations, with these then covering multiple billing periods. Does HA include any way to define billing periods within this code, so you could work out the days you get billed for each quarter (i.e. for example for my 3rd quarter bill above… define 10Aug to 9Nov that should roughly be the same every year) so you could then setup sensors for all four quarters with state/formulas that include the from/to dates to count?

Re the three different charge rates you have, what are the they? Looking at Origin and they have 0-1905mj (everyone will exceed that), then 1905-252,558mj that equates to consuming ~6,595m3 (or around $5,227 in a quarter) so I doubt any “Home users” would hit that 3rd billing tier…?

Correct up til this point. I googled a conversion and the first result was 37, but i see on my bill also 38.3 so good pickup.

My conversion factor is less than 1 so yes it will be individual. I’d be more inclined to make it it’s own sensor but same result.

No, i’m only converting the usage rate from MJ to M^3. This gives you a sensor that can be used on the energy dashboard as an entity with the current price. This however doesn’t account for supply charges so the total costs sensors incorporate the m^3 import rate above, plus the supply charges.

Now my rates are different to yours.


I have an annual rate for the first 7560, next 7560, next 18000 and even higher tiers.
According to the fine print its divided by 365 and multiplied by the days in the billing period and not carried forward.

The monthly total costs will have to be tiered in the same way, it goes up by the highest amount until the cap for that tier, then increases by less for the next tier etc etc.

For the daily calcs, i’m just going to consider the highest tier which will give me a consistent look at usage rather than actual cost.

Hi Sgt Batten,

Could you confirm that “counter.water_counter” is the ID of a water sensor in your ESPHome yaml for the water meter sensor? Just trying to work out what/how your pulling the water data and updating to work with my setup. The sensor section of my esphone yaml is:

sensor:
  - platform: pulse_meter
    name: "Water Flow Rate"
    id: "water_flow_rate"
    pin:
      number: 5
      inverted: true
      mode:
        input: true
        pullup: true
    internal_filter_mode: PULSE
    unit_of_measurement: "L/min"
    icon: "mdi:pump"
    internal_filter: 100ms
    timeout: 1min
    total:
      name: 'Water Consumption'
      id: water_consumption
      accuracy_decimals: 2
      unit_of_measurement: "L"
      state_class: "total_increasing"
      device_class: water
      icon: "mdi:water"
      filters:
      - multiply: 0.5

No it is a counter helper made in the HA UI. I have an automation that increments it 1 number each time my aqara door sensor (reed switch) turns on (twice per Lin my case, hence the * 0.5)

I don’t have a flow rate sensor figured out yet but will likely just use the built in derivative sensor in HA.

The yaml for the ESP8266 above with the ‘pulse_meter’, produces a flow rate. Sends into HA the following type data, giving 0.5L increases (per spin of the meter dial) that are captured also with a reed switch.

‘Water Flow Rate’: Sending state 13.44387 L/min with 2 decimals of accuracy
‘Water Consumption’: Sending state 88.50000 L with 2 decimals of accuracy

if your hammering the water, it will keep updating as it increases flow, turn off the tap and it will wait 59sec and then update back to 0.00 L/sec.

Any chance you post your configs ona Github repository, much easier to reverse engineer and customise when seeing the full picture?

yeah i’ll look to do that. I auto backup my configs to a private repo every night but i don’t want to share everything in that repo. I’ll see if I can share packages to a separate one but will take me some time.

I am not making any changes to this currently as I’m not using it yet, I just tested it and got basic functionality while i await more hardware.

There’s not much more than what I posted in water.yaml.

this helper:

and this automation

alias: Water Counter
description: ""
trigger:
  - platform: state
    from: "off"
    to: "on"
    entity_id:
      - binary_sensor.water_meter
condition: []
action:
  - service: counter.increment
    target:
      entity_id:
        - counter.water_counter
    data: {}
mode: queued
max: 10

everything else you’ve seen.

I found a problem with the days remaining in month sensor now that it’s december. It was calculating the difference from Jan this year instead of next year.

Fixed in the OP using this:

          {% set this = now().replace(hour=0).replace(minute=0).replace(second=0).replace(microsecond=0) %}
          {% set next = this.month + 1 if this.month + 1 <= 12 else 1 %}
          {% set last = this.replace(year=this.year + 1, month=1, day=1) if now().month == 12 else this.replace(month=next, day=1) %}
          {{ (last.date() - this.date()).days - 1 }}

Just noticed you have a “sensor.days_passed_in_year” just wondering how you define this sensor, as you don’t have it listed anywhere (above)?

template:
  - sensor:
      - name: Days Passed in Year
        unique_id: days_passed_in_year
        state: >
          {% set this = now().replace(hour=0).replace(minute=0).replace(second=0).replace(microsecond=0) %}
          {% set first = this.replace(month=1, day=1) %}
          {{ (this.date() - first.date()).days + 1 }}

Sgt Batten,

If your interested in trying it, I’ve uploaded my gas yaml files (/esphome and /packages) to: GitHub - jbhobson/Home-Assistant: Home Assistant - Water Meter (esp8266) for Goulburn Mulwaree Council

This is only with a single gas consumption tarrif rate, but it may be of assistant in your wanting to expand this to support your multiple tariff rates. The only problem I’ve encountered is that whilst the ‘Gas Total Cost Daily’ tracking entity shows the correct running total (MJ consumed cost + Daily connection fee), the energy dashboard shows a different cost. Upon investigation it appears that your formula to calculate the daily total is only adding in the consumed cost and failing to add the daily connection fee.

i.e. this section (& I assume the same error applies to the monthly and yearly totals also):

        state: >
          {% set supply = states('sensor.gas_daily_supply_charge') | float(0) %}
          {% set usage = states('sensor.gas_consumed_daily_mj') | float(0) * states('sensor.gas_cost_per_mj') | float(0) %}
          {{ (supply + usage) | round(2) }}

Have you encountered this issue also with your code, or would you have any suggestions?

PS: If you want to use the esphome yaml file, you can’t scp it to your HA instance. For some reason it rejects code updated this way, instead it works if you copy the contents and then edit the device in ESPHome dashboard, by pasting it into the open/being edited device config file.

BTW instead of adding correction factor, and converting to MJ etc in one step, I’ve defined them as individual steps so there is an sensor output for each. IMHO thought that even though this adds some extra sensors, this was handy to have the different m3 / corrected m3 / mj etc values to allow comparing to these on the retailers invoice and making sure they match.

I don’t have water or gas meters configured, you asked what code i had and nothing has changed since, I just made those at the time.

I don’t see why the daily calculation would not be working, it’s the same method as i use in energy.yaml for electricity and that works fine, i also see it reading as 0 in the energy dashboard when it is reading as 65c everywhere else. until i have a meter setup i can’t really investigate.

I have my own dashboard setup which i use instead of the energy dashboard so i’ve not paid attention to that page so far.

SgtBatten,

Could you assist, trying to update your code to below to have an action that caters for:

  • Peak - 7-9am and 5-8pm (weekdays)
  • Shoulder - 9am - 5pm and 8pm - 10pm (weekdays)
  • Off Peak - 10pm - 7am (weekdays) and ‘all weekend’

Your original code is:

alias: Set Electricity Tariff
description: ''
trigger:
  - platform: time
    at: '07:00:00'
  - platform: time
    at: '14:00:00'
  - platform: time
    at: '20:00:00'
  - platform: time
    at: '22:00:00'
  - platform: homeassistant
    event: start
condition: []
action:
  - service: select.select_option
    data:
      option: >-
        {% set t = now() %}  {%- if t.hour >=14 and t.hour <20 and
        is_state('binary_sensor.workday_sensor', 'on') %}
          peak
        {%- elif t.hour >= 22 or t.hour < 7 -%}
          off-peak
        {%- else -%}
          shoulder
        {%- endif -%}
    target:
      entity_id:
        - select.electricity_imported_power_daily
mode: single

Trying the following and can’t seem to workout the syntax / format to use, to amend the action data option section. Trying the following and failing:

    action:
      - service: select.select_option
        data:
          option: >-
            {% set t = now() %}  {%- if t.hour >=07 and t.hour <09 and
            is_state('binary_sensor.workday_sensor', 'on') %}
              peak
            {%- elif t.hour >= 17 or t.hour < 20 -%}
              peak
            {%- elif t.hour >= 22 or t.hour < 7 -%}
              off-peak
            {%- else -%}
              shoulder
            {%- endif -%}
        target:
          entity_id:
            - select.electricity_imported_power_daily

or

    action:
      - service: select.select_option
        data:
          option: >-
            {% set t = now() %}  {%- if ( t.hour >=07 and t.hour <09 ) or ( t.hour >=17 and t.hour <20 ) and
            is_state('binary_sensor.workday_sensor', 'on') %}
              peak
            {%- elif t.hour >= 22 or t.hour < 7 -%}
              off-peak
            {%- else -%}
              shoulder
            {%- endif -%}
        target:
          entity_id:
            - select.electricity_imported_power_daily

Any assistance appreciated. BTW the gas coding works great, seems like there’s a bug in the Energy Dashboard since an update going back a few months. Entities have the correct figures, but dashboard displays something else.

Since yours is most complex to define off-peak it’s easier to define the other two instead. Try this

            {% set t = now() %}  
            {%- if (( t.hour >= 7 and t.hour < 9 ) or ( t.hour >= 17 and t.hour < 20 )) and
            is_state('binary_sensor.workday_sensor', 'on') %}
              peak
            {%- elif (( t.hour >= 9 and t.hour < 17 ) or ( t.hour >= 20 and t.hour < 22 )) and 
            is_state('binary_sensor.workday_sensor', 'on') %}
              shoulder
            {%- else -%}
              off-peak
            {%- endif -%}