יום ראשון, 24 במרץ 2013

Solar systems yield Java / JavaScript development

Lately I've been asked to help with the monitoring systems of most of our Solar installations, which are hundreds of solar systems in Israel.

Each system is connected to the internet and has some kind of interface I can read it's data (if it's connected) and check these signs:
Solar system with shaded panels shown in black

- has the system lost connection lately (like the last week/month)
- is the power on right now?
- did it produce any energy yesterday and today?
- if it is connected more than a year, are there any interferences around the year and what's a year's yield?
- for each kW installed on the system, what's a years yield (normalized) ?
- what's the specific price for this system of NIS/kW and is it according to the financial plan?

I've started to learn Java (lots and lots of reading) and I've downloaded Eclipse that really helps a lot to design and study the syntax. I'll update here about the functions I'm writing and what each does, if you have suggestions I'd really appreciate Your feedback.

usually in Israel we refer to the 1650 kW a year per each kW installed.
so if I have a 55kWp system, It should produce about 90.75MW annualy. so if this system produces less I would flag it as an issue, unless it is designed for a certain azimuth / elevation which I can see in "solar degradation" charts what kind of yearly % will this system lack

I'm working on a Java application to scan these systems each night and write down a report.
I'm doing it step by step so here's a code to calculate how much time has passed (in days and in years) from the installation date until today:
some panels that show partial shading in the morning (probably a tree)

(I'm going to use native Java classes an no matter what the forums say, I'm not going to install any 3'rd party plugins for it...

// ----- Java Code : calculating difference between dates in days and years -----

import java.util.*;

public class Main {
    public static void main(String[] args){
        Calendar caln1 = new GregorianCalendar();
        Calendar caln2 = new GregorianCalendar();
        caln1.set(2010,1,1);
        // If you require a different date please insert one below remember to remove the "//" format: (Year,Month,Day)
        //caln2.set(2010,1,1);
        int daysb = daysCalcBetween(caln1.getTime(),caln2.getTime());
        System.out.println("Days passed = "    + daysb);
        double timeYears = daysb/365.25;
        System.out.println("in Years it's = " + timeYears);
    }
    public static int daysCalcBetween(Date d1,Date d2){
        return (int) ((d2.getTime()-d1.getTime())/(1000*60*60*24));
    }
}

// ----- END OF Java Code : calculating difference between dates in days and years -----

some system manufacturers provide a 'daily report' via email, so I've been starting to log these systems each day to get some perspective how different areas and climates provide different yields. I'm using Google Script to daily parse these emails into a Google Spreadsheet that provides some analytics on systems.

This is the actual daily yield of our systems for each 1kWp installed normalized and verified. from these analytics I could continue to develop a script that helps determine if a system is faulty, if it needs cleaning and to see who yields the best for each geographical area:

This is a 'live' graph that updates daily due to the JavaScript I've built in Google script:
the script is:
 -----
/* I am not a professional programmer so if you have any insight on how to optimize this script Your comments are more than welcome ! */

 function processSMA() {
  // getting the label target in gmail:
  var threads = GmailApp.getUserLabelByName('desiredLabel').getThreads();
var doc = SpreadsheetApp.openById("SpreadsheetDoc").getSheets()[0];
  var lastRow = doc.getLastRow();
  var lastCol = doc.getLastColumn();
  // This specific chart has indexes: a row for each date and a culomn for each system
  var indexDate = doc.getRange(1,1,lastRow,1).getValues();
  var indexDate1 = new Array()
  var indexSystem = doc.getRange(1, 1, 1, lastCol).getValues();
  var indexSystem1 = new Array();
 
  /* format date of index:
 since getRange receives a 2d array here, I need change it to a 1d array in order to search for indexes in it in the future. */

  for (i=0; i<lastRow;i++){
     indexDate1[i] = indexDate[i][0];
     if(indexDate1[i]>0){
     // I'm formating the date so that in the next indexing it would be easy to search for it
     indexDate1[i] = Utilities.formatDate(indexDate1[i], "GMT", "MM/dd/yyyy");
     }
  }
 
    for (i=0; i<lastCol;i++){
    // I'm removing white spaces to ensure proper indexing
    indexSystem1[i] = indexSystem[0][i].replace(/\s/g, "");
        }
  // garbage collector: remove unformatted old indexes:
  indexDate = null;
  indexSystem = null;
 
  // parsing the messages:
  for (var i = 0; i < threads.length; i++) {
  var messages = threads[i].getMessages();
  
    
     for (var j = 0; j < messages.length;j++) {
      // when dealing with large amount of emails, this is recommended...
       Utilities.sleep(1000);
      // Parse each message
       var date = Utilities.formatDate(messages[j].getDate(), "GMT", "MM/dd/yyyy")
       // row position:
       var rowPos = indexDate1.indexOf(date);
        // the subject of the email has the system name, the date and produced kWh today.
       var rawData = messages[j].getSubject().toString();
            
       // looking through the text for the data:
       var dataPosReport = rawData.search("Info Report");
       var dataPosDate = rawData.search(date);
       var dataPosProduction = rawData.search("Daily Production")
       var dataPoskWh = rawData.search("kWh")
     
       // and now to use this locations to create system and yield
       var systemName = rawData.slice(dataPosReport+12,dataPosDate-1).replace(/\s/g, "");
       var systemYield = rawData.slice(dataPosProduction+17,dataPoskWh);
       var colPos = indexSystem1.indexOf(systemName);
       if(colPos!=-1){
         doc.getRange(rowPos,colPos+1).setValue(systemYield);
       // getting rid of the email so It will not be parsed after it has been successful
         messages[j].moveToTrash();
       } else {
       // if a system has not been found or the operation was not successful log out the system, to assure the naming system is correct in the target spreadsheet.
       Logger.log(systemName);
       }
    }
  }
}

-----
again, I'm a graphic designer, not a professional programmer, it would mean a lot to me if any of you share your insight on how to improve this script further. comments are very much welcome !

ToDO:
1. with a given system evaluate if it is up to the 1650 kW/year per kW installed
2. compare the system yield and return of investment to it's contract information and what was promised to the client
3. learn to write a script that logs into each system through the internet, writes an XML or CSV for each system and evaluates system condition
4.  lots of work to be done (and this is on my spare time...) If you have some thoughts, links or anything I could learn from Your comments are welcome !

Z.