Predicting the productivity of a solar array with Perl

Putting Everything Together

What you eventually want is for the computer to download a forecast reaching many days in the future and, taking your power consumption profile into account, give you an idea of how much surplus power you are going to get in future days. A good strategy is to have a cronjob fetch the forecast file from Solcast right after midnight and then parse it with a program capable of making these estimations. The script in Listing 3 is a proof of concept for such a program.

Listing 3

solar_2.pl

01 #!/usr/bin/perl
02
03 # Usage: ./solar_2.pl forecast.csv profile.csv $power
04
05 use DateTime;
06
07 my @csv_forecast;
08 my @csv_profile;
09
10 my $line_number = "0";
11 open (my $fforecast, '<', $ARGV[0]) or die "Failed to open $ARGV[0]";
12 while ( my $line = <$fforecast>) {
13
14   $line =~ s/\R/\012/;
15   chomp ($line);
16
17   my ($power,$timestamp) = (split "," , $line)[0,3];
18   ${csv_forecast[$line_number]}{"power"} = $power;
19   ${csv_forecast[$line_number]}{"timestamp"} = $timestamp;
20
21   ++$line_number;
22 }
23 close ($fforecast);
24
25 $line_number = 0;
26 open (my $fprofile, '<', $ARGV[1]) or die "Failed to open $ARGV[1]";
27 while ( my $line = <$fprofile>) {
28
29   chomp ($line);
30
31   my ($timestamp,$percentage) = (split "," , $line);
32   ${csv_profile[$line_number]}{"timestamp"} = $timestamp;
33   ${csv_profile[$line_number]}{"percentage"} = $percentage;
34
35   ++$line_number;
36 }
37 close ($fprofile);
38
39 # For each 30 minutes period, calculate whether we are going to produce
40 # more power than we are going to consume (and therefore waste it),
41 # or whether we are going to consume more power than we produce (and
42 # therefore have deficit).
43
44 my $waste = "0";
45 my $deficit = "0";
46 my $produced = "0";
47
48 my ( $y,$m,$d,$h,$mt,$sec );
49 my ( $i,$j );
50 for ( $i = 1 ; $i < @csv_forecast ; ++$i )  {
51
52   ($y,$m,$d) = $csv_forecast[$i]{"timestamp"} =~ /^([\d]{4})\-([\d]{2})\-([\d]{2})/;
53   ($h,$mt,$sec) = $csv_forecast[$i]{"timestamp"} =~ /T([\d]{2})\:([\d]{2})\:([\d]{2})Z$/;
54   unless ( defined ($h) ) { ($h,$mt,$sec) = ( '0', '0', '0') };
55   my $forecast_time = DateTime->new(
56     year => $y,
57     month => $m,
58     day => $d,
59     hour => $h,
60     minute => $mt,
61     second => $sec,
62     time_zone => 'UTC'
63   );
64   $forecast_time->set_time_zone('local');
65
66   my $consumption;
67   my ( $hour,$minute );
68   for ( $j = 1 ; $j < @csv_profile ; ++$j ) {
69     ($hour,$minute) = $csv_profile[$j]{"timestamp"} =~ /([\d]{2})\:([\d]{2})$/;
70
71     if ( $hour == $forecast_time->hour() and $minute == $forecast_time->minute() ) {
72       $consumption = $csv_profile[$j]{"percentage"} * $ARGV[2] * 0.01;
73     }
74
75   }
76   if ( $consumption > ( $csv_forecast[$i]{"power"} * 0.5 )) {
77     $deficit += $consumption - ( $csv_forecast[$i]{"power"} * 0.5 );
78   } else {
79     $waste += ( $csv_forecast[$i]{"power"} * 0.5 ) - $consumption;
80   }
81
82   $produced += $csv_forecast[$i]{"power"} * 0.5;
83
84   # If the day has changed, print information for the day.
85   if ( $forecast_time->hour() == "0" and $forecast_time->minute() == "0" ) {
86     $forecast_time->subtract( days=> "1");
87     print "INFORMATION FOR DATE ".  $forecast_time->date() . "\n";
88     print "Total power produced will be $produced kWh\n";
89     print "About $deficit kWh will be taken from the grid (deficit)\n";
90     print "About $waste kWh will be produced but not used (wasted)\n\n";
91
92     $deficit = 0;
93     $waste = 0;
94     $produced = 0;
95   }
96 }
97
98 exit;

The script assumes solar arrays are working without battery backup and attempts to guess how much power your house will take from the grid and how much power will be produced but not used (Figure 7). Power considered "wasted" is what would be sold to the power supply company if you sign a smart grid contract. This script iterates over a given forecast file and calculates the time period covered by the file.

Figure 7: Output from solar_2.pl gives an approximation of how much power will be used and how much power will be wasted.

Lines 10-37 load the forecast and profile files to memory with the same approach as solar_1.pl. The profile file needs no removal of Windows-style newline terminations; therefore, it lacks a replacement regex such as the one featured on line 14. Lines 50 to 96 iterate through all the lines of the CSV forecast file, discarding the first one (which does not store a useful value). Although not really recommended by Perl gurus, I decided to use a C-type loop for readability. Lines 52-54 use regular expressions to extract the year, month, day, hour, minute, and second corresponding to the timestamp of the entry of the forecast file. Lines 55-64 create a DateTime object corresponding to the timestamp and adjust it to the local time zone.

Lines 68-75 look in the profile file for the entry corresponding to the timestamp it is currently analyzing and calculate the total power you expect the house to consume in that period. This calculation multiplies the total energy use expected for the day by the percentage of daily power use expected in the period corresponding to the timestamp, divided by 100. The result, in kilowatt-hours, is stored in the $consumption variable.

The calculations in lines 76-80 are the energy debt and excess. If the house consumes more power than is produced, the script notes the energy debt in the $deficit variable. Otherwise, excess power is noted in the $waste variable. The script also records the power produced so far by the solar array during the day in line 82.

Line 85 guesses whether the end of the day has arrived. If so, the script prints the information corresponding to the day just parsed and sets $deficit, $waste, and $produced to zero to start the next day anew.

Conclusion

The script in Listing 3 is a proof of concept and lacks input validation. It does not check whether the CSV files fed to it are correct and lacks appropriate exit statuses for input errors. However, it serves as a base on which to build a prediction system. You can easily set up a cronjob to download a forecast file from Solcast each day at midnight, generate a prediction with the script, and send it by email or post it to a website. The possibilities are endless (Figure 8).

Figure 8: Deficit, wasted power, and consumption curves through three days, generated by a variation of the script from Listing 3.

A more complex script that supports input validation and tracks the state of the battery banks is available at my gophersite [6].

The Author

Rubén Llorente is a mechanical engineer who ensures that the IT security measures for a small clinic are both legally compliant and safe. In addition, he is an OpenBSD enthusiast and a weapons collector.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News