Time of Day Calculations with VTScada
Someday I hope that it will be standard for utilities to provide a API that customers can use to calculate the current rates for energy, etc. Today however, we have to do it by hand.
My last post was a straightforward energy rate with a base charge, but I have a time of day rate at the house, so my rate is dependent on the month, day, hour and whether or not its a holiday.
This solution uses some advanced scripting.
Note, this is my first pass, I am actually testing to make sure it works as I write this. Also, I wasn't consistent with my thinking, but it works. If you have suggestions on how to clean it up, please let me know in the comments at the end.
Different Tag Types and Functions Used
To make this work I used a few different tag types and built in VTScada functions. Make sure you have the server clock set to 24hr to make this work as written.
Tags:
- Totalizer
- Calculation
- Context
What's the active rate?
For this task I started at the end and worked backwards. I created a Calculation tag that would record the current month cost, and a totalizer tag to calculate the current energy cost.
The calculation tag is straightforward, it sums the energy cost and base charge.
The totalizer tag multiplies the current power by the active rate
The active rate tag is where all the magic is. The [ActiveRate] determines which rate should be used for calculating energy cost at any moment.
There are three rates,
- [Standard]: This is the rate you would be charged with a straight KWHR only charge
- [Off-Peak]: This rate is used for holidays, weekends, and between 11pm-7am.
- [On-Peak]: This rate is used during the winter only and between 7am-12pm and again from 4pm-11pm.
Calculating the Active Rate
Before creating the expression for the [ActiveRate] I created my triggers. I was originally going to use trigger tags for the various times, but decided on calculation tags and using the built-in time and date functions.
With the tags here I can calculate the [ActiveRate]
What Month is it? [Month Peak]
Using the Date() function I can grab the month number. If its 12 (December) or (that's the || ) January or Febuary, then return 1, else return 0.
You can use TRUE/FALSE, X/Y, etc for this difference, but for this type of calculation, and for how I do [Holiday] I prefer to use a number.
What day is it? [DayofWeek]
I do something similar for getting the day of the week. What I want to know is whether or not its a weekday. If its a weekday I will return a 1.
What time is it? [TimeBlock1] ...
The three time blocks are similar. There are four timeblocks, but the fourth isn't calculated. I chose to leave out the one from 11pm to 7am, it is assumed that if non of the others are true, it must be this time block.
Is it a Holiday?
To determine if its a holiday or not, I created a Holiday tag and then added all the holidays together.
I could have OR'd them together to get the same result, and may change that in the future.
Something that I want to improve is have a static [Holiday] tag by adding an expression that figures out the year and concatenates that on the reference tag. By doing that I can just add 2021Holidays, 2022Holidays, etc. and never look at it again.
The Holidays that count for [Off-Peak] rates are on the NS Power Tariff page:
I create a calculation tag for each and manually add the month day for each -
Another Way to Handle Holidays
There is another way to do this where I change the [2020Holidays] context with just [Holidays] and then OR all of them together, but I decided that was too "messy".
This keeps the tag structure cleaner and sometimes cleanliness of code is more important than simplicity. Always think about what Future You will think about Past You. I know I question Past Me and my decisions when looking at code and designs all the time.
Putting the [ActiveRate] together
Now I have everything I need to put the [ActiveRate] together.
For expressions like this I use Notepad++ or something similar. You can format it nicely so you get all the commas, brackets, etc in the right place. When adding it directly expression box in VTScada it starts to get messy.
This expression is two nested IfElse statements. The first checks to see if its [On-Peak]. On-Peak is only valid when [TriggersMonth Peak] is true AND its in time block 1 or time block 3.
If that expression isn't true, I check to see if its [Off-Peak]. This is any holiday (or the Monday following) OR the weekend OR the missing time block.
Finally, if its not [On-Peak] or [Off-Peak] it must be [Standard].
Looping back to the start
The active rate flows back into the totalizer we started with and we are calculating the energy cost based on the time of the day.