C Application: Choosing an Electrical Plan

C Application: Choosing an Electrical Plan

People learning to program often struggle with how to decompose a problem into the steps necessary to write a program to solve that problem. This is one of a series of posts in which I take a problem and go through my decision-making process that leads to a program.

Background: In the spring of 2020, it was time to choose a new electrical plan and with my current provider I basically had two options. My home has a smart meter, so I am able to download my electrical usage in increments of 15 minutes. This allows me to apply each plan to actual data to see what the costs would have been.

Also relevant is that prior to April, 2020 I was going to work during the day and therefore wasn’t using as much electricity during the daytime.

Problem: Write a program to choose the cheapest electrical plan based on historical data. I assume that you understand statements, conditionals, loops, arrays, functions, strings, pointers, and file I/O.

You can find a video with more details at https://www.youtube.com/watch?v=rv0DwcdAgPM .


Design: Let’s look at the plans. This gives me an idea of what the relevant values are:

Plan 1 charges different rates for daytime and nightime. They are

      daytime:  8am <= time < 8pm    $0.088008/kWh
    nighttime:  8pm <= time < 8am    $0.078008/kWh
delivery cost:  $3.42 + $0.035448/kWh

Plan 2 charges the same rate each hour of the day. It’s cost is calculated as

     any time:  $0.078341/kWh
delivery cost:  $3.42 + $0.035448/kWh

The delivery costs are the same for both plans, so I could leave them out since I simply want to know which cost is cheapest. However, I will include them in case a comparison of future plans has them as different costs.

I can see that both plans determine my costs from the the kWh (i.e., kilowatt-hour) used for a time period, but that Plan 1 uses a different rate depending on the time of day. Therefore, I need to know the time of day and the kWh used.

Next, I want to know what I am working with with regard to the data, so I downloaded historical electrical usage for the period of January 1, 2020 to May 31, 2020; the data is in CSV format. Here are the first few lines (with my actual meter number changed):

ESIID,USAGE_DATE,REVISION_DATE,USAGE_START_TIME,USAGE_END_TIME,USAGE_KWH,ESTIMATED_ACTUAL,CONSUMPTION_GENERATION
123456,01/01/2020,01/03/2020 07:51:37,00:00,00:15,.043,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,00:15,00:30,.042,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,00:30,00:45,.064,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,00:45,01:00,.043,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,01:00,01:15,.043,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,01:15,01:30,.043,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,01:30,01:45,.042,A,Consumption
123456,01/01/2020,01/03/2020 07:51:37,01:45,02:00,.052,A,Consumption

The first line is a header line that tells me what the other lines represent, which I will need to deal with when processing the file in my program. I can see that the the columns relevant to my needs are

  • column 2: USAGE_DATE — this is the day of the year (necessary only if I want to restrict my comparison to a particular time of the year).
  • column 4: USAGE_START_TIME — this is the start of a 15-minute period for a given date
  • column 6: USAGE_KWH — this is the amount of electricity used

Why do I care about USAGE_DATE? I ended my employment on May 31, 2020 and am (at the time of this writing) at home during the daytime. Since I am using historical data to predict future costs, I chose to use the data from the month of May since it also reflects me being home during the daytime.

I think I know what to do now: for the month of May, 2020, get the electrical usage for each 15-minute time period and use it to calculate the cost if on Plan 1 and the cost if on Plan 2. This leads to this pseudocode:

/*    open file
      for each line of file
        get date, time, kwh
        if date in range
          if time is day
            update costs for plan 1 using day cost
          else
            update costs for plan 1 using night cost

          update costs for plan 2
      
      close file */

Final Program

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int checkDate(char buffer[], char* m, char t[], double* kwh) ;
double produceCostPlan1(char t[], double kwh) ;
double produceCostPlan2(double kwh) ;

int main(void) {
    FILE* fp;
    char* filename = "IntervalData.csv";
    char buffer[120];
    char* month = "05";  /* use May */
    char time[6];
    double kwh;
    int dateMatch;
    double costPlan1 = 3.42;  /* base delivery charge */
    double costPlan2 = 3.42;

    if( (fp = fopen(filename, "r")) == NULL ) {
        printf("unable to open %s\n", filename);
        exit(1);
    }

    fgets(buffer, sizeof(buffer), fp);

    while( fgets(buffer, sizeof(buffer), fp) != NULL ) {
        dateMatch = checkDate(buffer, month, time, &kwh);
        if(dateMatch) {
            costPlan1 += produceCostPlan1(time, kwh) ;
            costPlan2 += produceCostPlan2(kwh) ;
        }
    }

    fclose(fp);

    printf("cost plan 1 = $%.2f\n", costPlan1);
    printf("cost plan 2 = $%.2f\n", costPlan2);
}

int checkDate(char buffer[], char* m, char t[], double* kwh) {
    /*
    ESIID,USAGE_DATE,REVISION_DATE,USAGE_START_TIME,USAGE_END_TIME,USAGE_KWH,ESTIMATED_ACTUAL,CONSUMPTION_GENERATION
    123456,01/01/2020,01/03/2020 07:51:37,00:00,00:15,.043,A,Consumption
    
    ESIID                    : 123456
    USAGE_DATE               : 01/01/2020
    REVISION_DATE            : 01/03/2020 07:51:37
    USAGE_START_TIME         : 00:00
    USAGE_END_TIME           : 00:15
    USAGE_KWH                : .043
    ESTIMATED_ACTUAL         : A
    CONSUMPTION_GENERATION   : Consumption
    */

    char *token, *del = ",";
    char dateField[20];

    token = strtok(buffer, del);    /* meter ID, throw away */
    token = strtok(NULL, del);      /* date */
    strcpy(dateField, token);
    token = strtok(NULL, del);      /* revision date, throw away */
    token = strtok(NULL, del);      /* start time */
    strcpy(t, token);
    token = strtok(NULL, del);      /* end time, throw away */
    *kwh = atof(strtok(NULL, del)); /* kwh time */

    /* tokenize date field */
    token = strtok(dateField, "/");

    if( strcmp(token, m) == 0 )
        return 1; /* True, month matches */
    else
        return 0;
}


double produceCostPlan1(char t[], double kwh){
    /*
        plan 1: nights and weekends (>= 8pm to < 8am)
    
          base     $0
          days     $0.088008 per kWh = 8.8008 cents per kWh
          nights   $0.078008 per kWh = 7.8008 cents per kWh
      
          delivery $3.42 + $0.035448 per kWh
    */

    /* check if daytime */
    if( strcmp("08:00", t) <= 0 && strcmp(t, "20:00") < 0 ) 
        return kwh*0.088008 + kwh*0.035448;
    else
        return kwh*0.078008 + kwh*0.035448;
}


double produceCostPlan2(double kwh){
    /*
        plan 2: Secure 36 plan
    
          base     $0
          all day  $0.078341 per kWh = 7.8341 cents per kWh
      
          delivery $3.42 + $0.035448 per kWh
    */

    return kwh*0.078341 + kwh*0.035448;
}

Comments are closed.