Time of Use app - daily Supply Charge

I chucked this python script together last night and this morning - its a bit of a hack job, but it will probably do what you need.
I started including solar but it is not currently included, neither is the daily supply charge, but that’s fairly easy to add.

It calculates the hourly usage based on the feed ID in feed_id_import which should be a cumulative kWh feed of imported energy and then calculates the cost of that hour’s worth of energy based on the tarrif for the hour in question.

It then spits out a total of kWh and $ for each day

On my system, it produces output like this:

pi@emon-pi:~ $ ./dailycost.py
Daily totals: 0 : 0 kWh @ $ 0
Daily totals: 01 : 23.51611328125 kWh @ $ 7.580610351562498
Daily totals: 02 : 20.59033203125 kWh @ $ 6.2274365234375
Daily totals: 03 : 21.908203125 kWh @ $ 6.8537011718750005
Daily totals: 04 : 32.033203125 kWh @ $ 9.767094726562497
Daily totals: 05 : 23.73046875 kWh @ $ 7.2191748046874995
Daily totals: 06 : 26.61669921875 kWh @ $ 7.6351123046875005
Daily totals: 07 : 28.73193359375 kWh @ $ 9.758833007812498
Daily totals: 08 : 32.28173828125 kWh @ $ 12.026528320312499
Daily totals: 09 : 26.72314453125 kWh @ $ 7.4077783203125
Daily totals: 10 : 26.6982421875 kWh @ $ 9.02138671875
Daily totals: 11 : 21.82470703125 kWh @ $ 6.123593749999999
Daily totals: 12 : 24.81201171875 kWh @ $ 7.022583007812499
Daily totals: 13 : 9.101576653650227 kWh @ $ 1.6563322295585658

The total for today (shown in the last line) is “until now”
I’ve used “rough guess” values for the tarrifs, I didn’t actually look them up, so you’ll need to make sure you change them where it says in the script.

I don’t use HA, so I’m not sure what format you need data in to push it into HA, but it should be fairly simple for you to modify this with the required format.

On to the Python3 script!

#!/usr/bin/env python3

import datetime
import sys
import json
import requests
import time

emonCmsJson  = { }


emon_readKey = 'XXXXXXXXXXXXXXXXXXXXXXXXX' # Enter readAPIkey here - CHANGE THIS
emon_url        = 'http://emon-pi.local/feed/data.json' # If your EmonCMS has a different name or IP, update it here

feed_id_import = 91 # kWh feed Id of imported energy - CHANGE THIS
feed_id_export = 92 # kWh feed Id of exported energy - CHANGE THIS

# These should be the various tarrifs charged by your retailer
tarrif_rates = [0.18, 0.29, 0.59]  # CHANGE THESE

# If you have solar, update this with your feed-in rate
tarrif_feedin = 0.17 # CHANGE THIS

# These values are my standard tarrif periods, CHECK THESE
# update these with the index into the rates above, startng at 0
# First is the weekday times
tarrif_times_wd = [
    0, # 00:00 - 00:59
    0, # 01:00 - 01:59
    0, # 02:00 - 02:59
    0, # 03:00 - 03:59
    0, # 04:00 - 04:59
    0, # 05:00 - 05:59
    0, # 06:00 - 06:59
    1, # 07:00 - 07:59
    1, # 08:00 - 08:59
    1, # 09:00 - 09:59
    1, # 10:00 - 10:59
    1, # 11:00 - 11:59
    1, # 12:00 - 12:59
    1, # 13:00 - 13:59
    2, # 14:00 - 14:59
    2, # 15:00 - 15:59
    2, # 16:00 - 16:59
    2, # 17:00 - 17:59
    2, # 18:00 - 18:59
    2, # 19:00 - 19:59
    1, # 20:00 - 20:59
    1, # 21:00 - 21:59
    0, # 22:00 - 22:59
    0  # 23:00 - 23:59
]

# now for the weekend/pub holiday times
tarrif_times_we = [
    0, # 00:00 - 00:59
    0, # 01:00 - 01:59
    0, # 02:00 - 02:59
    0, # 03:00 - 03:59
    0, # 04:00 - 04:59
    0, # 05:00 - 05:59
    0, # 06:00 - 06:59
    1, # 07:00 - 07:59
    1, # 08:00 - 08:59
    1, # 09:00 - 09:59
    1, # 10:00 - 10:59
    1, # 11:00 - 11:59
    1, # 12:00 - 12:59
    1, # 13:00 - 13:59
    1, # 14:00 - 14:59
    1, # 15:00 - 15:59
    1, # 16:00 - 16:59
    1, # 17:00 - 17:59
    1, # 18:00 - 18:59
    1, # 19:00 - 19:59
    1, # 20:00 - 20:59
    1, # 21:00 - 21:59
    0, # 22:00 - 22:59
    0  # 23:00 - 23:59
]

# lets do this month's costs per day

# Start at 23:59 on the previous day, that gives us a starting value and then values up to hh:59:59
# for each hour period - this makes the claculations easier
month_start = datetime.datetime.today().replace(day=1,hour=0,minute=59,second=59,microsecond=0)
month_start = (month_start + datetime.timedelta(hours=-1)).timestamp() * 1000
now = datetime.datetime.now().timestamp() * 1000

payload_import = { 'apikey': emon_readKey, 'id': feed_id_import, 'start': month_start, 'end': now, 'interval': 3600 }

try:
    r = requests.get(emon_url, params=payload_import)
    if r.status_code != 200:
        print('HTTP response code is [' + str(r.status_code) + ']')
    else:
        last_kwh = 0
        last_day = 0
        day_total_kwh = 0
        day_total_cost = 0
        # need to iterate through the values returned, the timestamp is for the START of the period
        # so we need to drop everything back by 1 hr.
        for val in r.json():
            if last_kwh == 0:
                # Just starting
                last_kwh = val[1]
            else:
                val_date = datetime.datetime.fromtimestamp(val[0]/1000)
                day = val_date.strftime("%d")
                if day != last_day:
                    print('Daily totals:', last_day, ':', day_total_kwh, 'kWh @ $', day_total_cost)
                    day_total_kwh = 0
                    day_total_cost = 0
                    last_day = day
                dow = val_date.strftime("%w") # day of Week, Sunday is 0
                hr = int(val_date.strftime("%H"))
                interval_kwh = val[1] - last_kwh
                last_kwh = val[1]
                day_total_kwh += interval_kwh
                if dow == 0 or dow == 6:
                    # Use the weekend rates
                    kwh_rate = tarrif_rates[tarrif_times_we[hr]]
                else:
                    # use the weekday rates
                    kwh_rate = tarrif_rates[tarrif_times_wd[hr]]
                hr_cost = kwh_rate * interval_kwh
                day_total_cost += hr_cost
                #print(day, '-', hr, ': ', interval_kwh, ' $', hr_cost, '[$', kwh_rate, '/kWh]')
        print('Daily totals:', last_day, ':', day_total_kwh, 'kWh @ $', day_total_cost)



except ValueError as err:
    print('Caught http exception: ' + str(err))
    r.close()